1604 lines
54 KiB
C++
1604 lines
54 KiB
C++
#include "wzrdpvk.h"
|
|
#include "certca.h"
|
|
#include "cautil.h"
|
|
#include "CertRequesterContext.h"
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
//
|
|
// LocalContext Implementation.
|
|
// See CertRequestContext.h for method-level documentation.
|
|
//
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT LocalContext::BuildCSPList()
|
|
{
|
|
DWORD dwIndex = 0;
|
|
DWORD dwProviderType = 0;
|
|
DWORD cbSize = 0;
|
|
HRESULT hr = E_FAIL;
|
|
LPWSTR pwszProviderName = 0;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
//free the old memory
|
|
FreeProviders(m_pCertWizardInfo->dwCSPCount,
|
|
m_pCertWizardInfo->rgdwProviderType,
|
|
m_pCertWizardInfo->rgwszProvider);
|
|
|
|
m_pCertWizardInfo->dwCSPCount = 0;
|
|
m_pCertWizardInfo->rgdwProviderType = NULL;
|
|
m_pCertWizardInfo->rgwszProvider = NULL;
|
|
|
|
for (dwIndex = 0;
|
|
CryptEnumProvidersU(dwIndex, 0, 0, &dwProviderType, NULL, &cbSize);
|
|
dwIndex++)
|
|
{
|
|
pwszProviderName = (LPWSTR)WizardAlloc(cbSize);
|
|
if(NULL == pwszProviderName)
|
|
goto MemoryErr;
|
|
|
|
//get the provider name and type
|
|
if(!CryptEnumProvidersU
|
|
(dwIndex,
|
|
0,
|
|
0,
|
|
&dwProviderType,
|
|
pwszProviderName,
|
|
&cbSize))
|
|
goto CryptEnumProvidersUError;
|
|
|
|
m_pCertWizardInfo->dwCSPCount = dwIndex + 1;
|
|
m_pCertWizardInfo->rgdwProviderType = (DWORD *)WizardRealloc
|
|
(m_pCertWizardInfo->rgdwProviderType, sizeof(DWORD) * m_pCertWizardInfo->dwCSPCount);
|
|
|
|
if(NULL == m_pCertWizardInfo->rgdwProviderType)
|
|
goto MemoryErr;
|
|
|
|
m_pCertWizardInfo->rgwszProvider = (LPWSTR *)WizardRealloc
|
|
(m_pCertWizardInfo->rgwszProvider, sizeof(LPWSTR) * m_pCertWizardInfo->dwCSPCount);
|
|
|
|
if(NULL == m_pCertWizardInfo->rgwszProvider)
|
|
goto MemoryErr;
|
|
|
|
(m_pCertWizardInfo->rgdwProviderType)[dwIndex] = dwProviderType;
|
|
(m_pCertWizardInfo->rgwszProvider)[dwIndex] = pwszProviderName;
|
|
|
|
// Our only reference to this data should now be m_pCertWizardInfo->rgwszProvider.
|
|
pwszProviderName = NULL;
|
|
}
|
|
|
|
//we should have some CSPs
|
|
if(0 == m_pCertWizardInfo->dwCSPCount)
|
|
goto FailErr;
|
|
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
if (NULL != pwszProviderName) { WizardFree(pwszProviderName); }
|
|
|
|
//free the old memory
|
|
FreeProviders(m_pCertWizardInfo->dwCSPCount,
|
|
m_pCertWizardInfo->rgdwProviderType,
|
|
m_pCertWizardInfo->rgwszProvider);
|
|
|
|
m_pCertWizardInfo->dwCSPCount = 0;
|
|
m_pCertWizardInfo->rgdwProviderType = NULL;
|
|
m_pCertWizardInfo->rgwszProvider = NULL;
|
|
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CryptEnumProvidersUError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
SET_HRESULT(FailErr, E_FAIL);
|
|
}
|
|
|
|
BOOL LocalContext::CheckAccessPermission(IN HCERTTYPE hCertType)
|
|
{
|
|
BOOL fResult = FALSE;
|
|
HANDLE hClientToken = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
// First attempts to get the thread token. If this fails, acquires the
|
|
// process token. Finally, if that fails, returns NULL.
|
|
if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_TEMPLATES)) {
|
|
fResult = TRUE;
|
|
} else {
|
|
hClientToken = this->GetClientIdentity();
|
|
if (NULL == hClientToken)
|
|
goto GetClientIdentityError;
|
|
|
|
__try {
|
|
fResult = S_OK == CACertTypeAccessCheck(hCertType, hClientToken);
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
goto CACertTypeAccessCheckError;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
if (NULL != hClientToken) { CloseHandle(hClientToken); }
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CACertTypeAccessCheckError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(GetClientIdentityError, HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
BOOL LocalContext::CheckCAPermission(IN HCAINFO hCAInfo)
|
|
{
|
|
BOOL fResult = FALSE;
|
|
HANDLE hClientToken = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_CAS)) {
|
|
fResult = TRUE;
|
|
} else {
|
|
hClientToken = this->GetClientIdentity();
|
|
if (NULL == hClientToken)
|
|
goto GetClientIdentityError;
|
|
|
|
__try {
|
|
fResult = S_OK == CAAccessCheck(hCAInfo, hClientToken);
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
goto CAAccessCheckError;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
if (NULL != hClientToken) { CloseHandle(hClientToken); }
|
|
return fResult;
|
|
|
|
ErrorReturn:
|
|
fResult = FALSE;
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(CAAccessCheckError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(GetClientIdentityError, HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
HRESULT LocalContext::GetDefaultCSP(OUT BOOL *pfAllocateCSP)
|
|
{
|
|
DWORD cbData = 0;
|
|
HCRYPTPROV hProv = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
LPSTR pszName = NULL;
|
|
LPWSTR pwszName = NULL;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
if (NULL == pfAllocateCSP)
|
|
return E_INVALIDARG;
|
|
|
|
*pfAllocateCSP = FALSE;
|
|
|
|
//no provider has been selected
|
|
if(0 == m_pCertWizardInfo->dwProviderType)
|
|
return S_OK;
|
|
|
|
//return if user has selected both the dwProviderType
|
|
//or the provider name
|
|
if(NULL != m_pCertWizardInfo->pwszProvider)
|
|
return S_OK;
|
|
|
|
//get the default provider
|
|
if(!CryptAcquireContext(&hProv,
|
|
NULL,
|
|
NULL,
|
|
m_pCertWizardInfo->dwProviderType,
|
|
CRYPT_VERIFYCONTEXT))
|
|
goto Win32Err;
|
|
|
|
//get the provider name
|
|
if(!CryptGetProvParam(hProv,
|
|
PP_NAME,
|
|
NULL,
|
|
&cbData,
|
|
0) || (0==cbData))
|
|
goto Win32Err;
|
|
|
|
if(NULL == (pszName = (LPSTR)WizardAlloc(cbData)))
|
|
goto MemoryErr;
|
|
|
|
if(!CryptGetProvParam(hProv,
|
|
PP_NAME,
|
|
(BYTE *)pszName,
|
|
&cbData,
|
|
0))
|
|
goto Win32Err;
|
|
|
|
pwszName = MkWStr(pszName);
|
|
if(NULL == pwszName)
|
|
goto MemoryErr;
|
|
|
|
m_pCertWizardInfo->pwszProvider=(LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszName)+1));
|
|
if(NULL == m_pCertWizardInfo->pwszProvider)
|
|
goto MemoryErr;
|
|
|
|
*pfAllocateCSP = TRUE;
|
|
wcscpy(m_pCertWizardInfo->pwszProvider,pwszName);
|
|
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
if(NULL != hProv) { CryptReleaseContext(hProv, 0); }
|
|
if(NULL != pszName) { WizardFree(pszName); }
|
|
if(NULL != pwszName) { FreeWStr(pwszName); }
|
|
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
m_idsText = IDS_INVALID_CSP;
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(Win32Err, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
}
|
|
|
|
HRESULT LocalContext::Enroll(OUT DWORD *pdwStatus,
|
|
OUT HANDLE *pResult)
|
|
{
|
|
BOOL fHasNextCSP = TRUE;
|
|
BOOL fHasNextCA = TRUE;
|
|
BOOL fRequestIsCached;
|
|
BOOL fCreateRequest;
|
|
BOOL fFreeRequest;
|
|
BOOL fSubmitRequest;
|
|
CERT_BLOB renewCert;
|
|
CERT_ENROLL_INFO RequestInfo;
|
|
CERT_REQUEST_PVK_NEW CertRequestPvkNew;
|
|
CERT_REQUEST_PVK_NEW CertRenewPvk;
|
|
CRYPTUI_WIZ_CERT_CA CertCA;
|
|
DWORD dwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNKNOWN;
|
|
DWORD dwCSPIndex;
|
|
DWORD dwSavedGenKeyFlags;
|
|
HANDLE hRequest = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
LPWSTR pwszHashAlg = NULL;
|
|
|
|
//init 1st for error jump
|
|
ZeroMemory(&CertRenewPvk, sizeof(CertRenewPvk));
|
|
|
|
if (NULL == pResult)
|
|
return E_INVALIDARG;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
memset(&CertCA, 0, sizeof(CertCA));
|
|
memset(&RequestInfo, 0, sizeof(RequestInfo));
|
|
|
|
dwSavedGenKeyFlags = m_pCertWizardInfo->dwGenKeyFlags;
|
|
|
|
fCreateRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY));
|
|
fFreeRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY));
|
|
fSubmitRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY));
|
|
|
|
// An invalid combination of flags was specified.
|
|
if (FALSE == (fCreateRequest || fFreeRequest || fSubmitRequest))
|
|
return E_INVALIDARG;
|
|
|
|
// For FREE_ONLY and SUBMIT_ONLY, copy the request from the IN parameter.
|
|
if (0 != ((CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY) & m_pCertWizardInfo->dwFlags))
|
|
{
|
|
if (NULL == *pResult)
|
|
return E_INVALIDARG;
|
|
|
|
hRequest = *pResult;
|
|
}
|
|
|
|
// Initialize to false ... we need the marshalled parameters to know whether we can cache the request.
|
|
fRequestIsCached = FALSE;
|
|
|
|
// Iterate over each CA, performing a create and submit operation for each.
|
|
// Note that we can cache requests for certs if key archival is not needed.
|
|
//
|
|
if (fCreateRequest || fSubmitRequest)
|
|
{
|
|
for (IEnumCA CAEnumerator(m_pCertWizardInfo); TRUE; )
|
|
{
|
|
if (S_OK != (CAEnumerator.Next(&CertCA)))
|
|
{
|
|
if (!FAILED(hr))
|
|
hr=E_FAIL;
|
|
|
|
if (E_FAIL == hr)
|
|
m_pCertWizardInfo->idsText = IDS_NO_CA_FOR_ENROLL_REQUEST_FAILED;
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// Create a certificate request only if
|
|
// 1) This is not a submit-only or a free-only operation.
|
|
// 2) We don't already have a cached request.
|
|
// (We can cache requests which don't require key archival on the CA).
|
|
//
|
|
// The request is created by looping over available CSPs until one successfully generates
|
|
// the request.
|
|
//
|
|
if (TRUE == fCreateRequest && FALSE == fRequestIsCached)
|
|
{
|
|
BOOL fHasNextCSP = TRUE;
|
|
for (IEnumCSP CSPEnumerator(m_pCertWizardInfo); fHasNextCSP; )
|
|
{
|
|
_JumpCondition(S_OK != (hr = CSPEnumerator.Next(&dwCSPIndex)), ErrorReturn);
|
|
_JumpCondition(S_OK != (hr = CSPEnumerator.HasNext(&fHasNextCSP)), ErrorReturn);
|
|
|
|
// Each call to MarshallRequestParameters can change the dwGenKeyFlags of pCertWizardInfo
|
|
// if the CSP does not support the min key size contained in this field.
|
|
// As a result, we must reset the dwGenKeyFlags field to the desired value
|
|
// before every call to MarshallRequestParameters.
|
|
m_pCertWizardInfo->dwGenKeyFlags = dwSavedGenKeyFlags;
|
|
if (S_OK != (hr = ::MarshallRequestParameters
|
|
(dwCSPIndex,
|
|
m_pCertWizardInfo,
|
|
&renewCert,
|
|
&CertRequestPvkNew,
|
|
&CertRenewPvk,
|
|
&pwszHashAlg,
|
|
&RequestInfo)))
|
|
goto NextCSP;
|
|
|
|
if (NULL != hRequest)
|
|
{
|
|
::FreeRequest(hRequest);
|
|
hRequest = NULL;
|
|
}
|
|
|
|
hr = ::CreateRequest
|
|
(m_pCertWizardInfo->dwFlags,
|
|
m_pCertWizardInfo->dwPurpose,
|
|
CertCA.pwszCAName,
|
|
CertCA.pwszCALocation,
|
|
((CRYPTUI_WIZ_CERT_RENEW & m_pCertWizardInfo->dwPurpose) ? &renewCert : NULL),
|
|
((CRYPTUI_WIZ_CERT_RENEW & m_pCertWizardInfo->dwPurpose) ? &CertRenewPvk : NULL),
|
|
m_pCertWizardInfo->fNewKey,
|
|
&CertRequestPvkNew,
|
|
pwszHashAlg,
|
|
(LPWSTR)m_pCertWizardInfo->pwszDesStore,
|
|
m_pCertWizardInfo->dwStoreFlags,
|
|
&RequestInfo,
|
|
&hRequest);
|
|
|
|
// Process the return value:
|
|
if (S_OK == hr)
|
|
{
|
|
// Success, get rid of whatever error text we have from past creations:
|
|
m_pCertWizardInfo->idsText = 0;
|
|
|
|
// We're done if we don't need to submit the request.
|
|
_JumpCondition(!fSubmitRequest, CommonReturn);
|
|
|
|
// Cache the request if we don't need support for key archival.
|
|
fRequestIsCached = 0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL);
|
|
break;
|
|
}
|
|
else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// E_ACCESSDENIED could indicate one of several different error conditions. Map this
|
|
// to an resource identifier which details the possible causes of failure, and try again...
|
|
m_pCertWizardInfo->idsText = IDS_NO_ACCESS_TO_ICERTREQUEST2;
|
|
}
|
|
else if (NTE_BAD_ALGID == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// NTE_BAD_ALGID indicates that the CSP didn't support the algorithm type required
|
|
// by the template. Map this to a resource identifier that details the possible causes
|
|
// of failure, and try again...
|
|
m_pCertWizardInfo->idsText = IDS_CSP_BAD_ALGTYPE;
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// The user cancelled the operation. Don't try to enroll any longer.
|
|
goto ErrorReturn;
|
|
}
|
|
else
|
|
{
|
|
// It's an error, but we don't need to map it to special text. Just keep processing...
|
|
}
|
|
|
|
// We're out of CSPs, and we haven't yet created the request!
|
|
if (!fHasNextCSP)
|
|
{
|
|
// If the template doesn't require key archival, we're done. Otherwise, we've got to
|
|
// try the other CAs. Note that if we had a mechanism for knowing whether it was the
|
|
// key archival step
|
|
if (0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL))
|
|
goto ErrorReturn;
|
|
else
|
|
{
|
|
::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
|
|
goto NextCA;
|
|
}
|
|
}
|
|
|
|
NextCSP:
|
|
::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
|
|
}
|
|
}
|
|
|
|
// Submit the request only if this is not a create-only or a free-only operation:
|
|
//
|
|
if (TRUE == fSubmitRequest)
|
|
{
|
|
hr = ::SubmitRequest
|
|
(hRequest,
|
|
FALSE,
|
|
m_pCertWizardInfo->dwPurpose,
|
|
m_pCertWizardInfo->fConfirmation,
|
|
m_pCertWizardInfo->hwndParent,
|
|
(LPWSTR)m_pCertWizardInfo->pwszConfirmationTitle,
|
|
m_pCertWizardInfo->idsConfirmTitle,
|
|
CertCA.pwszCALocation,
|
|
CertCA.pwszCAName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwStatus,
|
|
(PCCERT_CONTEXT *)pResult);
|
|
if (S_OK == hr)
|
|
{
|
|
// Success, get rid of whatever error text we have from past submits:
|
|
m_pCertWizardInfo->idsText = 0;
|
|
|
|
// If we've successfully submitted or pended
|
|
goto CommonReturn;
|
|
}
|
|
else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// E_ACCESSDENIED could indicate one of several different error conditions. Map this
|
|
// to an resource identifier which details the possible causes of failure, and try again...
|
|
m_pCertWizardInfo->idsText = IDS_SUBMIT_NO_ACCESS_TO_ICERTREQUEST2;
|
|
}
|
|
|
|
// Some error has occured.
|
|
// If it's a non-CA related error, give up...
|
|
_JumpCondition(dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR &&
|
|
dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_DENIED &&
|
|
dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_CONNECTION_FAILED,
|
|
ErrorReturn);
|
|
|
|
// Otherwise, try another CA...
|
|
}
|
|
NextCA:;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
// Write the request to pResult for a create only operation:
|
|
if (hr == S_OK && 0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_CREATE_ONLY))
|
|
{
|
|
*pResult = hRequest;
|
|
}
|
|
|
|
// Write the status code, if requested.
|
|
if (NULL != pdwStatus) { *pdwStatus = dwStatus; }
|
|
|
|
// Free resources.
|
|
if (NULL != hRequest && fFreeRequest) { ::FreeRequest(hRequest); }
|
|
::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
|
|
|
|
if (NULL != CertRenewPvk.pwszKeyContainer)
|
|
{
|
|
WizardFree((LPVOID)CertRenewPvk.pwszKeyContainer);
|
|
}
|
|
if (NULL != CertRenewPvk.pwszProvider)
|
|
{
|
|
WizardFree((LPVOID)CertRenewPvk.pwszProvider);
|
|
}
|
|
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
}
|
|
|
|
|
|
HRESULT LocalContext::QueryRequestStatus(IN HANDLE hRequest, OUT CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO *pQueryInfo)
|
|
{
|
|
HRESULT hr;
|
|
|
|
if (!QueryRequest(hRequest, pQueryInfo))
|
|
goto QueryRequestError;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
return hr;
|
|
|
|
SET_HRESULT(QueryRequestError, GetLastError());
|
|
}
|
|
|
|
HRESULT KeySvcContext::QueryRequestStatus(IN HANDLE hRequest, OUT CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO *pQueryInfo)
|
|
{
|
|
DWORD dwErr = 0;
|
|
DWORD dwIndex = 0;
|
|
HRESULT hr = E_FAIL;
|
|
KEYSVCC_HANDLE hKeyService = NULL;
|
|
KEYSVC_TYPE dwServiceType = KeySvcMachine;
|
|
LPSTR pszMachineName = NULL;
|
|
PKEYSVC_PROVIDER_INFO pProviderInfo = NULL;
|
|
ULONG cProvider = 0;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
if (0 != (hr = ::KeyOpenKeyService(pszMachineName,
|
|
dwServiceType,
|
|
(LPWSTR)(m_pCertWizardInfo->pwszAccountName), // Service name if necessary
|
|
NULL, // no authentication string right now
|
|
NULL,
|
|
&hKeyService)))
|
|
goto KeyOpenKeyServiceError;
|
|
|
|
if (0 != (hr = ::KeyQueryRequestStatus(hKeyService, hRequest, pQueryInfo)))
|
|
goto KeyQueryRequestStatusError;
|
|
|
|
hr = S_OK;
|
|
ErrorReturn:
|
|
if (NULL != hKeyService) { KeyCloseKeyService(hKeyService, NULL); }
|
|
if (NULL != pszMachineName) { FreeMBStr(NULL,pszMachineName); }
|
|
return hr;
|
|
|
|
|
|
TRACE_ERROR(KeyOpenKeyServiceError);
|
|
TRACE_ERROR(KeyQueryRequestStatusError);
|
|
}
|
|
|
|
HRESULT LocalContext::Initialize()
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
HANDLE LocalContext::GetClientIdentity()
|
|
{
|
|
HANDLE hHandle = NULL;
|
|
HANDLE hClientToken = NULL;
|
|
HANDLE hProcessToken = NULL;
|
|
HRESULT hr;
|
|
|
|
// Step 1: attempt to acquire the thread token.
|
|
hHandle = GetCurrentThread();
|
|
if (NULL == hHandle)
|
|
goto GetThreadTokenError;
|
|
|
|
if (!OpenThreadToken(hHandle,
|
|
TOKEN_QUERY,
|
|
TRUE, // open as self
|
|
&hClientToken))
|
|
goto GetThreadTokenError;
|
|
|
|
// We got the thread token:
|
|
goto GetThreadTokenSuccess;
|
|
|
|
// Step 2: we've failed to acquire the thread token,
|
|
// try to get the process token.
|
|
GetThreadTokenError:
|
|
if (hHandle != NULL) { CloseHandle(hHandle); }
|
|
|
|
// We failed to get the thread token, now try to acquire the process token:
|
|
hHandle = GetCurrentProcess();
|
|
if (NULL == hHandle)
|
|
goto GetProcessHandleError;
|
|
|
|
if (!OpenProcessToken(hHandle,
|
|
TOKEN_DUPLICATE,
|
|
&hProcessToken))
|
|
goto OpenProcessTokenError;
|
|
|
|
if(!DuplicateToken(hProcessToken,
|
|
SecurityImpersonation,
|
|
&hClientToken))
|
|
goto DuplicateTokenError;
|
|
|
|
GetThreadTokenSuccess:
|
|
CommonReturn:
|
|
if (NULL != hHandle) { CloseHandle(hHandle); }
|
|
if (NULL != hProcessToken) { CloseHandle(hProcessToken); }
|
|
|
|
return hClientToken;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(DuplicateTokenError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(GetProcessHandleError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(OpenProcessTokenError, HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
//
|
|
// KeySvcContext Implementation.
|
|
// See requesters.h for method-level documentation.
|
|
//
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
|
|
HRESULT KeySvcContext::BuildCSPList()
|
|
{
|
|
DWORD dwErr = 0;
|
|
DWORD dwIndex = 0;
|
|
HRESULT hr = E_FAIL;
|
|
KEYSVCC_HANDLE hKeyService = NULL;
|
|
KEYSVC_TYPE dwServiceType = KeySvcMachine;
|
|
LPSTR pszMachineName = NULL;
|
|
PKEYSVC_PROVIDER_INFO pProviderInfo = NULL;
|
|
ULONG cProvider = 0;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
// Free the memory currently associated with the CSP fields:
|
|
FreeProviders(m_pCertWizardInfo->dwCSPCount,
|
|
m_pCertWizardInfo->rgdwProviderType,
|
|
m_pCertWizardInfo->rgwszProvider);
|
|
|
|
m_pCertWizardInfo->dwCSPCount = 0;
|
|
m_pCertWizardInfo->rgdwProviderType = NULL;
|
|
m_pCertWizardInfo->rgwszProvider = NULL;
|
|
|
|
//get the psz machine name
|
|
if(NULL == m_pCertWizardInfo->pwszMachineName)
|
|
goto FailErr;
|
|
|
|
if(!MkMBStr(NULL, 0, m_pCertWizardInfo->pwszMachineName, &pszMachineName))
|
|
goto MkMBStrError;
|
|
|
|
//connect to the key service
|
|
dwServiceType = NULL != m_pCertWizardInfo->pwszAccountName ? KeySvcService : KeySvcMachine;
|
|
|
|
if (0 != (hr = ::KeyOpenKeyService(pszMachineName,
|
|
dwServiceType,
|
|
(LPWSTR)(m_pCertWizardInfo->pwszAccountName), // Service name if necessary
|
|
NULL, // no authentication string right now
|
|
NULL,
|
|
&hKeyService)))
|
|
goto KeyOpenKeyServiceError;
|
|
|
|
//get the providers
|
|
if(0 != (hr = KeyEnumerateProviders
|
|
(hKeyService,
|
|
NULL,
|
|
&cProvider,
|
|
&pProviderInfo)))
|
|
goto KeyEnumerateProvidersError;
|
|
|
|
//copy the provider information
|
|
m_pCertWizardInfo->dwCSPCount = cProvider;
|
|
m_pCertWizardInfo->rgdwProviderType = (DWORD *)WizardAlloc(sizeof(DWORD) * cProvider);
|
|
if (NULL == m_pCertWizardInfo->rgdwProviderType)
|
|
goto MemoryErr;
|
|
|
|
memset(m_pCertWizardInfo->rgdwProviderType, 0, sizeof(DWORD) * cProvider);
|
|
|
|
m_pCertWizardInfo->rgwszProvider = (LPWSTR *)WizardAlloc(sizeof(LPWSTR) * cProvider);
|
|
if (NULL == m_pCertWizardInfo->rgwszProvider)
|
|
goto MemoryErr;
|
|
|
|
memset(m_pCertWizardInfo->rgwszProvider, 0, sizeof(LPWSTR) * cProvider);
|
|
|
|
for(dwIndex=0; dwIndex < cProvider; dwIndex++)
|
|
{
|
|
(m_pCertWizardInfo->rgdwProviderType)[dwIndex] = pProviderInfo[dwIndex].ProviderType;
|
|
(m_pCertWizardInfo->rgwszProvider)[dwIndex] = WizardAllocAndCopyWStr((LPWSTR)(pProviderInfo[dwIndex].Name.Buffer));
|
|
|
|
if (NULL == (m_pCertWizardInfo->rgwszProvider)[dwIndex])
|
|
goto MemoryErr;
|
|
}
|
|
|
|
//we should have some CSPs
|
|
if(0 == m_pCertWizardInfo->dwCSPCount)
|
|
goto FailErr;
|
|
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
if (NULL != hKeyService) { KeyCloseKeyService(hKeyService, NULL); }
|
|
if (NULL != pszMachineName) { FreeMBStr(NULL,pszMachineName); }
|
|
if (NULL != pProviderInfo) { WizardFree(pProviderInfo); }
|
|
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
// Free and invalidate our provider lists:
|
|
|
|
FreeProviders(m_pCertWizardInfo->dwCSPCount,
|
|
m_pCertWizardInfo->rgdwProviderType,
|
|
m_pCertWizardInfo->rgwszProvider);
|
|
|
|
m_pCertWizardInfo->dwCSPCount = 0;
|
|
m_pCertWizardInfo->rgdwProviderType = NULL;
|
|
m_pCertWizardInfo->rgwszProvider = NULL;
|
|
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(FailErr, E_FAIL);
|
|
SET_HRESULT(KeyEnumerateProvidersError, HRESULT_FROM_WIN32(hr));
|
|
SET_HRESULT(KeyOpenKeyServiceError, HRESULT_FROM_WIN32(hr));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
SET_HRESULT(MkMBStrError, HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
BOOL KeySvcContext::CheckAccessPermission(IN HCERTTYPE hCertType)
|
|
{
|
|
BOOL fResult = FALSE;
|
|
LPWSTR *awszCurrentType = NULL;
|
|
LPWSTR *awszTypeName = NULL;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
{
|
|
SetLastError(E_POINTER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_TEMPLATES)) {
|
|
return TRUE;
|
|
}
|
|
|
|
if(NULL != m_pCertWizardInfo->awszAllowedCertTypes)
|
|
{
|
|
if(S_OK == CAGetCertTypeProperty(hCertType, CERTTYPE_PROP_DN, &awszTypeName))
|
|
{
|
|
if(NULL != awszTypeName)
|
|
{
|
|
if(NULL != awszTypeName[0])
|
|
{
|
|
awszCurrentType = m_pCertWizardInfo->awszAllowedCertTypes;
|
|
|
|
while(NULL != *awszCurrentType)
|
|
{
|
|
if(wcscmp(*awszCurrentType, awszTypeName[0]) == 0)
|
|
{
|
|
return TRUE;
|
|
}
|
|
awszCurrentType++;
|
|
}
|
|
}
|
|
|
|
CAFreeCertTypeProperty(hCertType, awszTypeName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL KeySvcContext::CheckCAPermission(IN HCAINFO hCAInfo)
|
|
{
|
|
LPWSTR *wszCAName = NULL;
|
|
LPWSTR *wszCurrentCA = NULL;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
{
|
|
SetLastError(E_POINTER);
|
|
return FALSE;
|
|
}
|
|
|
|
if (0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_CAS)) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (NULL != m_pCertWizardInfo->awszValidCA)
|
|
{
|
|
if(S_OK == CAGetCAProperty(hCAInfo, CA_PROP_NAME, &wszCAName))
|
|
{
|
|
if(NULL != wszCAName)
|
|
{
|
|
if(NULL != wszCAName[0])
|
|
{
|
|
wszCurrentCA = m_pCertWizardInfo->awszValidCA;
|
|
|
|
while(*wszCurrentCA)
|
|
{
|
|
if(0 == wcscmp(*wszCurrentCA, wszCAName[0]))
|
|
{
|
|
return TRUE;
|
|
}
|
|
wszCurrentCA++;
|
|
}
|
|
}
|
|
|
|
CAFreeCAProperty(hCAInfo, wszCAName);
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT KeySvcContext::GetDefaultCSP(OUT BOOL *pfAllocateCSP)
|
|
{
|
|
DWORD dwDefaultFlag = 0;
|
|
HRESULT hr = E_FAIL;
|
|
LPSTR pszMachineName = NULL;
|
|
LPWSTR pwszName = NULL;
|
|
KEYSVC_TYPE dwServiceType = KeySvcMachine;
|
|
KEYSVCC_HANDLE hKeyService = NULL;
|
|
PKEYSVC_PROVIDER_INFO pKeyProviderInfo = NULL;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
if (NULL == pfAllocateCSP)
|
|
return E_INVALIDARG;
|
|
|
|
*pfAllocateCSP = FALSE;
|
|
|
|
//no provider has been selected
|
|
if(0 == m_pCertWizardInfo->dwProviderType)
|
|
return S_OK;
|
|
|
|
//return if user has selected both the dwProviderType
|
|
//or the provider name
|
|
if(NULL != m_pCertWizardInfo->pwszProvider)
|
|
return S_OK;
|
|
|
|
//get the psz machine name
|
|
if(NULL == m_pCertWizardInfo->pwszMachineName)
|
|
goto InvalidArgErr;
|
|
|
|
if(!MkMBStr(NULL, 0, m_pCertWizardInfo->pwszMachineName, &pszMachineName))
|
|
goto Win32Err;
|
|
|
|
dwServiceType = NULL != m_pCertWizardInfo->pwszAccountName ? KeySvcService : KeySvcMachine;
|
|
|
|
//connect to the key service
|
|
if (0 != (hr = KeyOpenKeyService
|
|
(pszMachineName,
|
|
dwServiceType,
|
|
(LPWSTR)(m_pCertWizardInfo->pwszAccountName), // Service name if necessary
|
|
NULL, // no authentication string right now
|
|
NULL,
|
|
&hKeyService)))
|
|
{
|
|
m_idsText = IDS_RPC_CALL_FAILED;
|
|
goto Win32Err;
|
|
}
|
|
|
|
//get the default provider name
|
|
if(0 != (hr = KeyGetDefaultProvider
|
|
(hKeyService,
|
|
m_pCertWizardInfo->dwProviderType,
|
|
0,
|
|
NULL,
|
|
&dwDefaultFlag,
|
|
&pKeyProviderInfo)))
|
|
{
|
|
m_idsText = IDS_RPC_CALL_FAILED;
|
|
goto Win32Err;
|
|
}
|
|
|
|
pwszName = (LPWSTR)(pKeyProviderInfo->Name.Buffer);
|
|
if(NULL == pwszName)
|
|
goto FailErr;
|
|
|
|
m_pCertWizardInfo->pwszProvider = (LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszName)+1));
|
|
if(NULL == m_pCertWizardInfo->pwszProvider)
|
|
goto MemoryErr;
|
|
|
|
*pfAllocateCSP = TRUE;
|
|
wcscpy(m_pCertWizardInfo->pwszProvider, pwszName);
|
|
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
if (NULL != pKeyProviderInfo) { WizardFree(pKeyProviderInfo); }
|
|
if (NULL != hKeyService) { KeyCloseKeyService(hKeyService, NULL); }
|
|
if (NULL != pszMachineName) { FreeMBStr(NULL,pszMachineName); }
|
|
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(InvalidArgErr, E_INVALIDARG);
|
|
SET_HRESULT(Win32Err, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(MemoryErr, E_OUTOFMEMORY);
|
|
SET_HRESULT(FailErr, E_FAIL);
|
|
}
|
|
|
|
HRESULT WhistlerMachineContext::Enroll(OUT DWORD *pdwStatus,
|
|
IN OUT HANDLE *pResult)
|
|
{
|
|
BOOL fRequestIsCached;
|
|
BOOL fCreateRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY));
|
|
BOOL fFreeRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY));
|
|
BOOL fSubmitRequest = 0 == (m_pCertWizardInfo->dwFlags & (CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY));
|
|
CERT_BLOB renewCert;
|
|
CERT_ENROLL_INFO RequestInfo;
|
|
CERT_REQUEST_PVK_NEW CertRequestPvkNew;
|
|
CERT_REQUEST_PVK_NEW CertRenewPvk;
|
|
CRYPTUI_WIZ_CERT_CA CertCA;
|
|
DWORD dwFlags;
|
|
DWORD dwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNKNOWN;
|
|
DWORD dwCSPIndex;
|
|
DWORD dwSavedGenKeyFlags;
|
|
HANDLE hRequest = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
KEYSVCC_HANDLE hKeyService = NULL;
|
|
KEYSVC_TYPE ktServiceType;
|
|
LPSTR pszMachineName = NULL;
|
|
LPWSTR pwszHashAlg = NULL;
|
|
|
|
//init 1st for error jump
|
|
ZeroMemory(&CertRenewPvk, sizeof(CertRenewPvk));
|
|
|
|
if (NULL == pResult)
|
|
return E_INVALIDARG;
|
|
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
memset(&renewCert, 0, sizeof(renewCert));
|
|
memset(&CertCA, 0, sizeof(CertCA));
|
|
memset(&RequestInfo, 0, sizeof(RequestInfo));
|
|
|
|
dwSavedGenKeyFlags = m_pCertWizardInfo->dwGenKeyFlags;
|
|
|
|
// An invalid combination of flags was specified.
|
|
if (FALSE == (fCreateRequest || fFreeRequest || fSubmitRequest))
|
|
return E_INVALIDARG;
|
|
|
|
// For FREE_ONLY and SUBMIT_ONLY, copy the request from the IN parameter.
|
|
if (0 != ((CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY) & m_pCertWizardInfo->dwFlags))
|
|
{
|
|
if (NULL == *pResult)
|
|
return E_INVALIDARG;
|
|
|
|
hRequest = *pResult;
|
|
}
|
|
|
|
if(!MkMBStr(NULL, 0, m_pCertWizardInfo->pwszMachineName, &pszMachineName))
|
|
goto MkMBStrError;
|
|
|
|
ktServiceType = NULL != m_pCertWizardInfo->pwszAccountName ? KeySvcService : KeySvcMachine;
|
|
|
|
hr = ::KeyOpenKeyService
|
|
(pszMachineName,
|
|
ktServiceType,
|
|
(LPWSTR)(m_pCertWizardInfo->pwszAccountName),
|
|
NULL,
|
|
NULL,
|
|
&hKeyService);
|
|
_JumpConditionWithExpr(S_OK != hr, KeyOpenKeyServiceError, m_idsText = IDS_RPC_CALL_FAILED);
|
|
|
|
// Initialize to false ... we need the marshalled parameters to know whether we can cache the request.
|
|
fRequestIsCached = FALSE;
|
|
|
|
// Iterate over each CA, performing a create and submit operation for each.
|
|
// Note that we can cache requests for certs if key archival is not needed.
|
|
//
|
|
if (fCreateRequest || fSubmitRequest)
|
|
{
|
|
for (IEnumCA CAEnumerator(m_pCertWizardInfo); TRUE; )
|
|
{
|
|
if (S_OK != (CAEnumerator.Next(&CertCA)))
|
|
{
|
|
if(!FAILED(hr))
|
|
hr=E_FAIL;
|
|
|
|
if (E_FAIL == hr)
|
|
m_pCertWizardInfo->idsText = IDS_NO_CA_FOR_ENROLL_REQUEST_FAILED;
|
|
|
|
goto ErrorReturn;
|
|
}
|
|
|
|
// Create a certificate request only if
|
|
// 1) This is not a submit-only or a free-only operation.
|
|
// 2) We don't already have a cached request.
|
|
// (We can cache requests which don't require key archival on the CA).
|
|
//
|
|
// The request is created by looping over available CSPs until one successfully generates
|
|
// the request.
|
|
//
|
|
|
|
if (TRUE == fCreateRequest && FALSE == fRequestIsCached)
|
|
{
|
|
BOOL fHasNextCSP = TRUE;
|
|
for (IEnumCSP CSPEnumerator(m_pCertWizardInfo); fHasNextCSP; )
|
|
{
|
|
_JumpCondition(S_OK != (hr = CSPEnumerator.Next(&dwCSPIndex)), ErrorReturn);
|
|
_JumpCondition(S_OK != (hr = CSPEnumerator.HasNext(&fHasNextCSP)), ErrorReturn);
|
|
|
|
// Each call to MarshallRequestParameters can change the dwGenKeyFlags of pCertWizardInfo
|
|
// if the CSP does not support the min key size contained in this field.
|
|
// As a result, we must reset the dwGenKeyFlags field to the desired value
|
|
// before every call to MarshallRequestParameters.
|
|
m_pCertWizardInfo->dwGenKeyFlags = dwSavedGenKeyFlags;
|
|
if (S_OK != (hr = ::MarshallRequestParameters
|
|
(dwCSPIndex,
|
|
m_pCertWizardInfo,
|
|
&renewCert,
|
|
&CertRequestPvkNew,
|
|
&CertRenewPvk,
|
|
&pwszHashAlg,
|
|
&RequestInfo)))
|
|
goto NextCSP;
|
|
|
|
if (NULL != hRequest)
|
|
{
|
|
this->FreeRequest(hKeyService, pszMachineName, &hRequest);
|
|
hRequest = NULL;
|
|
}
|
|
|
|
hr = this->CreateRequest
|
|
(hKeyService,
|
|
pszMachineName,
|
|
CertCA.pwszCALocation,
|
|
CertCA.pwszCAName,
|
|
&CertRequestPvkNew,
|
|
&renewCert,
|
|
&CertRenewPvk,
|
|
pwszHashAlg,
|
|
&RequestInfo,
|
|
&hRequest);
|
|
|
|
// Process the return value:
|
|
if (S_OK == hr)
|
|
{
|
|
// Success, get rid of whatever error text we have from past creations:
|
|
m_pCertWizardInfo->idsText = 0;
|
|
|
|
// We're done if we don't need to submit the request.
|
|
_JumpCondition(!fSubmitRequest, CommonReturn);
|
|
|
|
// Cache the request if we don't need support for key archival.
|
|
fRequestIsCached = 0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL);
|
|
break;
|
|
}
|
|
else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// E_ACCESSDENIED could indicate one of several different error conditions. Map this
|
|
// to an resource identifier which details the possible causes of failure, and try again...
|
|
m_pCertWizardInfo->idsText = IDS_NO_ACCESS_TO_ICERTREQUEST2;
|
|
}
|
|
else if (NTE_BAD_ALGID == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// NTE_BAD_ALGID indicates that the CSP didn't support the algorithm type required
|
|
// by the template. Map this to a resource identifier that details the possible causes
|
|
// of failure, and try again...
|
|
m_pCertWizardInfo->idsText = IDS_CSP_BAD_ALGTYPE;
|
|
}
|
|
else if (HRESULT_FROM_WIN32(ERROR_CANCELLED) == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// The user cancelled the operation. Don't try to enroll any longer.
|
|
goto ErrorReturn;
|
|
}
|
|
else
|
|
{
|
|
// It's an error, but we don't need to map it to special text. Just keep processing...
|
|
}
|
|
|
|
// We're out of CSPs, and we haven't yet created the request!
|
|
if (!fHasNextCSP)
|
|
{
|
|
// If the template doesn't require key archival, we're done. Otherwise, we've got to
|
|
// try the other CAs. Note that if we had a mechanism for knowing whether it was the
|
|
// key archival step
|
|
if (0 == (CertRequestPvkNew.dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL))
|
|
goto ErrorReturn;
|
|
else
|
|
{
|
|
::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
|
|
goto NextCA;
|
|
}
|
|
}
|
|
|
|
NextCSP:
|
|
::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
|
|
}
|
|
}
|
|
|
|
if (TRUE == fSubmitRequest)
|
|
{
|
|
hr = this->SubmitRequest
|
|
(hKeyService,
|
|
pszMachineName,
|
|
CertCA.pwszCALocation,
|
|
CertCA.pwszCAName,
|
|
hRequest,
|
|
(PCCERT_CONTEXT *)pResult,
|
|
&dwStatus);
|
|
if (S_OK == hr)
|
|
{
|
|
// Success, get rid of whatever error text we have from past submits:
|
|
m_pCertWizardInfo->idsText = 0;
|
|
|
|
// If we've successfully submitted or pended
|
|
goto CommonReturn;
|
|
}
|
|
else if (E_ACCESSDENIED == HRESULT_FROM_WIN32(hr))
|
|
{
|
|
// E_ACCESSDENIED could indicate one of several different error conditions. Map this
|
|
// to an resource identifier which details the possible causes of failure, and try again...
|
|
m_pCertWizardInfo->idsText = IDS_SUBMIT_NO_ACCESS_TO_ICERTREQUEST2;
|
|
}
|
|
|
|
// Some error has occured.
|
|
// If it's a non-CA related error, give up...
|
|
_JumpCondition(dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR &&
|
|
dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_DENIED &&
|
|
dwStatus != CRYPTUI_WIZ_CERT_REQUEST_STATUS_CONNECTION_FAILED,
|
|
ErrorReturn);
|
|
|
|
// Otherwise, try another CA...
|
|
}
|
|
NextCA:;
|
|
}
|
|
}
|
|
|
|
CommonReturn:
|
|
// Write the request to pResult for a create only operation:
|
|
if (hr == S_OK && 0 != (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_CREATE_ONLY))
|
|
{
|
|
*pResult = hRequest;
|
|
}
|
|
|
|
// Write the status code, if requested.
|
|
if (NULL != pdwStatus) { *pdwStatus = dwStatus; }
|
|
|
|
// Free resources.
|
|
if (NULL != hRequest && TRUE == fFreeRequest) { this->FreeRequest(hKeyService, pszMachineName, hRequest); }
|
|
if (NULL != hKeyService) { ::KeyCloseKeyService(hKeyService, NULL); }
|
|
if (NULL != pszMachineName) { ::FreeMBStr(NULL,pszMachineName); }
|
|
if (NULL != CertRenewPvk.pwszKeyContainer)
|
|
{
|
|
WizardFree((LPVOID)CertRenewPvk.pwszKeyContainer);
|
|
}
|
|
if (NULL != CertRenewPvk.pwszProvider)
|
|
{
|
|
WizardFree((LPVOID)CertRenewPvk.pwszProvider);
|
|
}
|
|
|
|
::FreeRequestParameters(&pwszHashAlg, &RequestInfo);
|
|
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(KeyOpenKeyServiceError, hr);
|
|
SET_HRESULT(MkMBStrError, HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
HRESULT WhistlerMachineContext::CreateRequest
|
|
(IN KEYSVCC_HANDLE hKeyService,
|
|
IN LPSTR pszMachineName,
|
|
IN LPWSTR pwszCALocation,
|
|
IN LPWSTR pwszCAName,
|
|
IN PCERT_REQUEST_PVK_NEW pKeyNew,
|
|
IN CERT_BLOB *pCert,
|
|
IN PCERT_REQUEST_PVK_NEW pRenewKey,
|
|
IN LPWSTR pwszHashAlg,
|
|
IN PCERT_ENROLL_INFO pRequestInfo,
|
|
OUT HANDLE *phRequest)
|
|
{
|
|
CERT_BLOB PKCS7Blob;
|
|
CERT_BLOB renewCert;
|
|
DWORD dwFlags = m_pCertWizardInfo->dwFlags;
|
|
|
|
dwFlags &= ~(CRYPTUI_WIZ_SUBMIT_ONLY | CRYPTUI_WIZ_FREE_ONLY);
|
|
dwFlags |= CRYPTUI_WIZ_CREATE_ONLY;
|
|
|
|
// Create the certificate request...
|
|
return ::KeyEnroll_V2
|
|
(hKeyService,
|
|
pszMachineName,
|
|
TRUE,
|
|
m_pCertWizardInfo->dwPurpose,
|
|
dwFlags,
|
|
(LPWSTR)(m_pCertWizardInfo->pwszAccountName),
|
|
NULL,
|
|
(CRYPTUI_WIZ_CERT_ENROLL & m_pCertWizardInfo->dwPurpose) ? TRUE : FALSE,
|
|
pwszCALocation,
|
|
pwszCAName,
|
|
m_pCertWizardInfo->fNewKey,
|
|
pKeyNew,
|
|
pCert,
|
|
pRenewKey,
|
|
pwszHashAlg,
|
|
(LPWSTR)m_pCertWizardInfo->pwszDesStore,
|
|
m_pCertWizardInfo->dwStoreFlags,
|
|
pRequestInfo,
|
|
(LPWSTR)m_pCertWizardInfo->pwszRequestString,
|
|
0,
|
|
NULL,
|
|
phRequest,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
|
|
HRESULT WhistlerMachineContext::SubmitRequest
|
|
(IN KEYSVCC_HANDLE hKeyService,
|
|
IN LPSTR pszMachineName,
|
|
IN LPWSTR pwszCALocation,
|
|
IN LPWSTR pwszCAName,
|
|
IN HANDLE hRequest,
|
|
OUT PCCERT_CONTEXT *ppCertContext,
|
|
OUT DWORD *pdwStatus)
|
|
{
|
|
CERT_BLOB HashBlob;
|
|
CERT_BLOB PKCS7Blob;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
memset(&HashBlob, 0, sizeof(HashBlob));
|
|
memset(&PKCS7Blob, 0, sizeof(PKCS7Blob));
|
|
|
|
|
|
DWORD dwFlags = m_pCertWizardInfo->dwFlags;
|
|
|
|
dwFlags &= ~(CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_FREE_ONLY);
|
|
dwFlags |= CRYPTUI_WIZ_SUBMIT_ONLY;
|
|
|
|
// Submit the certificate request...
|
|
hr = ::KeyEnroll_V2
|
|
(hKeyService,
|
|
pszMachineName,
|
|
TRUE,
|
|
m_pCertWizardInfo->dwPurpose,
|
|
dwFlags,
|
|
(LPWSTR)(m_pCertWizardInfo->pwszAccountName),
|
|
NULL,
|
|
(CRYPTUI_WIZ_CERT_ENROLL & m_pCertWizardInfo->dwPurpose) ? TRUE : FALSE,
|
|
pwszCALocation,
|
|
pwszCAName,
|
|
m_pCertWizardInfo->fNewKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&hRequest,
|
|
&PKCS7Blob,
|
|
&HashBlob,
|
|
pdwStatus);
|
|
|
|
if (S_OK == hr && CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED == *pdwStatus)
|
|
{
|
|
hr = this->ToCertContext
|
|
(&PKCS7Blob,
|
|
&HashBlob,
|
|
pdwStatus,
|
|
ppCertContext);
|
|
}
|
|
|
|
if (NULL != HashBlob.pbData) { ::WizardFree(HashBlob.pbData); }
|
|
if (NULL != PKCS7Blob.pbData) { ::WizardFree(PKCS7Blob.pbData); }
|
|
|
|
return hr;
|
|
}
|
|
|
|
void WhistlerMachineContext::FreeRequest
|
|
(IN KEYSVCC_HANDLE hKeyService,
|
|
IN LPSTR pszMachineName,
|
|
IN HANDLE hRequest)
|
|
{
|
|
DWORD dwFlags = m_pCertWizardInfo->dwFlags;
|
|
|
|
dwFlags &= ~(CRYPTUI_WIZ_CREATE_ONLY | CRYPTUI_WIZ_SUBMIT_ONLY);
|
|
dwFlags |= CRYPTUI_WIZ_FREE_ONLY;
|
|
|
|
::KeyEnroll_V2
|
|
(hKeyService,
|
|
pszMachineName,
|
|
TRUE,
|
|
0,
|
|
dwFlags,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
&hRequest,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
HRESULT KeySvcContext::ToCertContext(IN CERT_BLOB *pPKCS7Blob,
|
|
IN CERT_BLOB *pHashBlob,
|
|
OUT DWORD *pdwStatus,
|
|
OUT PCCERT_CONTEXT *ppCertContext)
|
|
{
|
|
HCERTSTORE hCertStore = NULL;
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (NULL == pPKCS7Blob || NULL == pHashBlob || NULL == ppCertContext)
|
|
return E_INVALIDARG;
|
|
|
|
//get the certificate store from the PKCS7 for the remote case
|
|
if (!::CryptQueryObject(CERT_QUERY_OBJECT_BLOB,
|
|
pPKCS7Blob,
|
|
CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED,
|
|
CERT_QUERY_FORMAT_FLAG_ALL,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&hCertStore,
|
|
NULL,
|
|
NULL))
|
|
{
|
|
if (NULL != pdwStatus) { *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; }
|
|
goto FailError;
|
|
}
|
|
|
|
//find the certificate based on the hash
|
|
if (NULL == (*ppCertContext = ::CertFindCertificateInStore
|
|
(hCertStore,
|
|
X509_ASN_ENCODING,
|
|
0,
|
|
CERT_FIND_SHA1_HASH,
|
|
pHashBlob,
|
|
NULL)))
|
|
{
|
|
if (NULL != pdwStatus) { *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; }
|
|
goto FailError;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
if(NULL != hCertStore) { CertCloseStore(hCertStore, 0); }
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
if (NULL != pdwStatus && 0 == *pdwStatus) { *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_KEYSVC_FAILED; }
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(FailError, E_FAIL);
|
|
}
|
|
|
|
|
|
HRESULT KeySvcContext::Initialize()
|
|
{
|
|
if (NULL == m_pCertWizardInfo)
|
|
return E_POINTER;
|
|
|
|
// We don't need to download the list of allowed templates if we're not going
|
|
// to be performing the access check anyway.
|
|
if (0 == (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_TEMPLATES))
|
|
{
|
|
//for the remote enrollment, we have to get the allowed cert type
|
|
//list from the key service.
|
|
if(!::GetCertTypeName(m_pCertWizardInfo))
|
|
{
|
|
m_idsText = IDS_NO_VALID_CERT_TEMPLATE;
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
|
|
// We don't need to download the list of allowed CAs if we're not going
|
|
// to be performing the access check anyway
|
|
if (0 == (m_pCertWizardInfo->dwFlags & CRYPTUI_WIZ_ALLOW_ALL_CAS))
|
|
{
|
|
if(!::GetCAName(m_pCertWizardInfo))
|
|
{
|
|
m_idsText = IDS_NO_CA_FOR_ENROLL;
|
|
return HRESULT_FROM_WIN32(GetLastError());
|
|
}
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
//
|
|
//
|
|
// CertRequesterContext: implementation of abstract superclass.
|
|
// See requesters.h for method-level documentation.
|
|
//
|
|
//
|
|
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
|
|
HRESULT CertRequesterContext::MakeDefaultCertRequesterContext
|
|
(OUT CertRequesterContext **ppRequesterContext)
|
|
{
|
|
CERT_WIZARD_INFO *pCertWizardInfo = NULL;
|
|
HRESULT hr;
|
|
|
|
pCertWizardInfo = (CERT_WIZARD_INFO *)WizardAlloc(sizeof(CERT_WIZARD_INFO));
|
|
_JumpCondition(NULL == pCertWizardInfo, MemoryError);
|
|
|
|
hr = MakeCertRequesterContext
|
|
(NULL,
|
|
NULL,
|
|
0,
|
|
pCertWizardInfo,
|
|
ppRequesterContext,
|
|
NULL);
|
|
_JumpCondition(S_OK != hr, MakeCertRequesterContextError);
|
|
|
|
hr = S_OK;
|
|
CommonReturn:
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
if (NULL != pCertWizardInfo) { WizardFree(pCertWizardInfo); }
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(MakeCertRequesterContextError, hr);
|
|
SET_HRESULT(MemoryError, E_OUTOFMEMORY);
|
|
}
|
|
|
|
HRESULT CertRequesterContext::MakeCertRequesterContext
|
|
(IN LPCWSTR pwszAccountName,
|
|
IN LPCWSTR pwszMachineName,
|
|
IN DWORD dwCertOpenStoreFlags,
|
|
IN CERT_WIZARD_INFO *pCertWizardInfo,
|
|
OUT CertRequesterContext **ppRequesterContext,
|
|
OUT UINT *pIDSText)
|
|
{
|
|
BOOL fMachine = FALSE;
|
|
DWORD const dwLocalUserNameSize = UNLEN + 1;
|
|
DWORD const dwLocalMachineNameSize = MAX_COMPUTERNAME_LENGTH + 1;
|
|
HRESULT hr = E_FAIL;
|
|
UINT idsText = NULL == pIDSText ? 0 : *pIDSText;
|
|
WCHAR wszLocalUserName[dwLocalUserNameSize] = { 0 };
|
|
WCHAR wszLocalMachineName[dwLocalMachineNameSize] = { 0 };
|
|
|
|
// Input validation:
|
|
if (NULL == pCertWizardInfo || NULL == ppRequesterContext)
|
|
return E_INVALIDARG;
|
|
|
|
// Should not have assigned values to these fields yet:
|
|
if (NULL != pCertWizardInfo->pwszAccountName || NULL != pCertWizardInfo->pwszMachineName)
|
|
return E_INVALIDARG;
|
|
|
|
if(!GetUserNameU(wszLocalUserName, (DWORD *)&dwLocalUserNameSize))
|
|
{
|
|
idsText=IDS_FAIL_TO_GET_USER_NAME;
|
|
goto Win32Error;
|
|
}
|
|
|
|
if(!GetComputerNameU(wszLocalMachineName, (DWORD *)&dwLocalMachineNameSize))
|
|
{
|
|
idsText=IDS_FAIL_TO_GET_COMPUTER_NAME;
|
|
goto Win32Error;
|
|
}
|
|
|
|
// Map all unspecified values to defaults:
|
|
//
|
|
|
|
// Default #1: NULL pwszAccountName indicates current user _iff_ pwszMachineName is NULL.
|
|
if (NULL == pwszAccountName && NULL == pwszMachineName)
|
|
{ pwszAccountName = wszLocalUserName; }
|
|
|
|
// Default #2: NULL pwszMachineName indicates local machine.
|
|
if (NULL == pwszMachineName)
|
|
{ pwszMachineName = wszLocalMachineName; }
|
|
|
|
// Default #3: NULL pwszAccountName and non-NULL pwszMachineName indicates machine enrollment.
|
|
fMachine = (NULL == pwszAccountName ||
|
|
(0 != _wcsicmp(pwszAccountName, wszLocalUserName)) ||
|
|
(0 != _wcsicmp(pwszMachineName, wszLocalMachineName)));
|
|
|
|
// Default #4: dwCertOpenStoreFlags == 0 defaults to CERT_SYSTEM_STORE_LOCAL_MACHINE
|
|
// for machine enrollment, CERT_SYSTEM_STORE_CURRENT_USER for user enrollment.
|
|
if (0 == dwCertOpenStoreFlags)
|
|
{ dwCertOpenStoreFlags = fMachine ? CERT_SYSTEM_STORE_LOCAL_MACHINE : CERT_SYSTEM_STORE_CURRENT_USER; }
|
|
|
|
// Now that we've mapped unspecified values to defaults, assign the wizard's fields
|
|
// with these values:
|
|
//
|
|
if (NULL != pwszAccountName)
|
|
{
|
|
pCertWizardInfo->pwszAccountName = (LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszAccountName) + 1));
|
|
_JumpConditionWithExpr(NULL == pCertWizardInfo->pwszAccountName, MemoryError, idsText = IDS_OUT_OF_MEMORY);
|
|
wcscpy((LPWSTR)pCertWizardInfo->pwszAccountName, pwszAccountName);
|
|
}
|
|
|
|
pCertWizardInfo->pwszMachineName = (LPWSTR)WizardAlloc(sizeof(WCHAR) * (wcslen(pwszMachineName) + 1));
|
|
_JumpConditionWithExpr(NULL == pCertWizardInfo->pwszMachineName, MemoryError, idsText = IDS_OUT_OF_MEMORY);
|
|
wcscpy((LPWSTR)pCertWizardInfo->pwszMachineName, pwszMachineName);
|
|
|
|
pCertWizardInfo->fMachine = fMachine;
|
|
pCertWizardInfo->dwStoreFlags = dwCertOpenStoreFlags;
|
|
|
|
// We need keysvc if:
|
|
//
|
|
// 1) We're doing machine enrollment (we need to run under the local machine's context).
|
|
// 2) An account _other_ than the current user on the local machine is specified.
|
|
// (we need to run under another user's context).
|
|
//
|
|
if (TRUE == fMachine)
|
|
{
|
|
KEYSVC_TYPE ktServiceType;
|
|
KEYSVC_OPEN_KEYSVC_INFO OpenKeySvcInfo = { sizeof(KEYSVC_OPEN_KEYSVC_INFO), 0 };
|
|
KEYSVCC_HANDLE hKeyService = NULL;
|
|
LPSTR pszMachineName = NULL;
|
|
|
|
ktServiceType = NULL != pwszAccountName ? KeySvcService : KeySvcMachine;
|
|
_JumpConditionWithExpr(!MkMBStr(NULL, 0, pwszMachineName, &pszMachineName), MkMBStrError, idsText = IDS_OUT_OF_MEMORY);
|
|
|
|
// See if we're enrolling for a W2K or a Whistler machine:
|
|
hr = KeyOpenKeyService
|
|
(pszMachineName,
|
|
ktServiceType,
|
|
(LPWSTR)pwszAccountName,
|
|
NULL,
|
|
&OpenKeySvcInfo,
|
|
&hKeyService);
|
|
_JumpConditionWithExpr(S_OK != hr, KeyOpenKeyServiceError, idsText = IDS_RPC_CALL_FAILED);
|
|
|
|
switch (OpenKeySvcInfo.ulVersion)
|
|
{
|
|
case KEYSVC_VERSION_WHISTLER:
|
|
*ppRequesterContext = new WhistlerMachineContext(pCertWizardInfo);
|
|
break;
|
|
case KEYSVC_VERSION_W2K:
|
|
default:
|
|
hr = E_UNEXPECTED;
|
|
goto KeyOpenKeyServiceError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// We're requesting a cert for ourselves: we don't need keysvc.
|
|
*ppRequesterContext = new LocalContext(pCertWizardInfo);
|
|
}
|
|
|
|
if (NULL == *ppRequesterContext)
|
|
goto MemoryError;
|
|
|
|
hr = S_OK;
|
|
|
|
CommonReturn:
|
|
return hr;
|
|
|
|
ErrorReturn:
|
|
if (NULL != pCertWizardInfo->pwszMachineName) { WizardFree((LPVOID)pCertWizardInfo->pwszMachineName); }
|
|
if (NULL != pCertWizardInfo->pwszAccountName) { WizardFree((LPVOID)pCertWizardInfo->pwszAccountName); }
|
|
pCertWizardInfo->pwszMachineName = NULL;
|
|
pCertWizardInfo->pwszAccountName = NULL;
|
|
|
|
// Assign error text if specified:
|
|
if (NULL != pIDSText) { *pIDSText = idsText; }
|
|
goto CommonReturn;
|
|
|
|
SET_HRESULT(MemoryError, E_OUTOFMEMORY);
|
|
SET_HRESULT(KeyOpenKeyServiceError, hr);
|
|
SET_HRESULT(MkMBStrError, HRESULT_FROM_WIN32(GetLastError()));
|
|
SET_HRESULT(Win32Error, HRESULT_FROM_WIN32(GetLastError()));
|
|
}
|
|
|
|
CertRequesterContext::~CertRequesterContext()
|
|
{
|
|
if (NULL != m_pCertWizardInfo)
|
|
{
|
|
if (NULL != m_pCertWizardInfo->pwszMachineName) { WizardFree((LPVOID)m_pCertWizardInfo->pwszMachineName); }
|
|
if (NULL != m_pCertWizardInfo->pwszAccountName) { WizardFree((LPVOID)m_pCertWizardInfo->pwszAccountName); }
|
|
m_pCertWizardInfo->pwszMachineName = NULL;
|
|
m_pCertWizardInfo->pwszAccountName = NULL;
|
|
}
|
|
}
|
|
|