1473 lines
49 KiB
C++
1473 lines
49 KiB
C++
|
//+-------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1997 - 2000
|
||
|
//
|
||
|
// File: cautil.cpp
|
||
|
//
|
||
|
//--------------------------------------------------------------------------
|
||
|
|
||
|
#include "wzrdpvk.h"
|
||
|
#include "certca.h"
|
||
|
#include "cautil.h"
|
||
|
#include "CertRequesterContext.h"
|
||
|
#include "CertDSManager.h"
|
||
|
#include "CertRequester.h"
|
||
|
|
||
|
//------------------------------------------------------------
|
||
|
//
|
||
|
// Utility memory deallocate functions.
|
||
|
//
|
||
|
//------------------------------------------------------------
|
||
|
|
||
|
|
||
|
void CAFreeCertTypeExtensionsArray
|
||
|
(
|
||
|
IN LPVOID pCertExtensionsArray,
|
||
|
int dwArrayLen
|
||
|
)
|
||
|
{
|
||
|
for (int i=0; i<dwArrayLen; i++)
|
||
|
{
|
||
|
// Ignore return value.
|
||
|
CAFreeCertTypeExtensions(NULL, ((PCERT_EXTENSIONS *)pCertExtensionsArray)[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WizardFreePDWORDArray
|
||
|
(IN LPVOID pdwArray,
|
||
|
int dwArrayLen
|
||
|
)
|
||
|
{
|
||
|
for (int i=0; i<dwArrayLen; i++)
|
||
|
{
|
||
|
WizardFree(((DWORD **)pdwArray)[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void WizardFreeLPWSTRArray
|
||
|
(IN LPVOID pwszArray,
|
||
|
int dwArrayLen
|
||
|
)
|
||
|
{
|
||
|
for (int i=0; i<dwArrayLen; i++)
|
||
|
{
|
||
|
WizardFree(((LPWSTR *)pwszArray)[i]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
typedef void (* PDEALLOCATOR)(void *, int);
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
// CAUtilGetCADisplayName
|
||
|
//
|
||
|
//--------------------------------------------------------------------
|
||
|
BOOL CAUtilGetCADisplayName(IN DWORD dwCAFindFlags,
|
||
|
IN LPWSTR pwszCAName,
|
||
|
OUT LPWSTR *ppwszCADisplayName)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
CertDSManager *pDSManager = NULL;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
HCAINFO hCAInfo = NULL;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
LPWSTR *ppwszDisplayNameProp = NULL;
|
||
|
|
||
|
// Input validation:
|
||
|
_JumpCondition(NULL == pwszCAName || NULL == ppwszCADisplayName, CLEANUP);
|
||
|
|
||
|
// Init:
|
||
|
*ppwszCADisplayName = NULL;
|
||
|
|
||
|
hr = CAFindByName
|
||
|
(pwszCAName,
|
||
|
NULL,
|
||
|
dwCAFindFlags,
|
||
|
&hCAInfo);
|
||
|
_JumpCondition(NULL == hCAInfo || FAILED(hr), CLEANUP);
|
||
|
|
||
|
hr=CAGetCAProperty
|
||
|
(hCAInfo,
|
||
|
CA_PROP_DISPLAY_NAME,
|
||
|
&ppwszDisplayNameProp);
|
||
|
_JumpCondition(NULL == ppwszDisplayNameProp || FAILED(hr), CLEANUP);
|
||
|
|
||
|
*ppwszCADisplayName = WizardAllocAndCopyWStr(ppwszDisplayNameProp[0]);
|
||
|
_JumpCondition(NULL == *ppwszCADisplayName, CLEANUP);
|
||
|
|
||
|
fResult = TRUE;
|
||
|
|
||
|
CLEANUP:
|
||
|
if(NULL != ppwszDisplayNameProp) { CAFreeCAProperty(hCAInfo, ppwszDisplayNameProp); }
|
||
|
if(NULL != hCAInfo) { CACloseCA(hCAInfo); }
|
||
|
|
||
|
return fResult;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
// CheckSubjectRequirement
|
||
|
//
|
||
|
//--------------------------------------------------------------------
|
||
|
BOOL CheckSubjectRequirement(HCERTTYPE hCurCertType,
|
||
|
LPWSTR pwszInputCertDNName)
|
||
|
{
|
||
|
DWORD dwFlags;
|
||
|
|
||
|
//check the subject requirement of the cert type
|
||
|
if (S_OK != (CAGetCertTypeFlagsEx
|
||
|
(hCurCertType,
|
||
|
CERTTYPE_SUBJECT_NAME_FLAG,
|
||
|
&dwFlags)))
|
||
|
return FALSE;
|
||
|
|
||
|
// Supported if
|
||
|
// 1) Subject name requirement is not set
|
||
|
// 2) Cert DN Name is supplied.
|
||
|
return
|
||
|
(0 == (CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT & dwFlags)) ||
|
||
|
(NULL != pwszInputCertDNName);
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
// Make sure the CSP supported by the cert type is consistent
|
||
|
// with user's requirement and the local machine's CSP list
|
||
|
//
|
||
|
//--------------------------------------------------------------------
|
||
|
BOOL CheckCertTypeCSP(IN CERT_WIZARD_INFO *pCertWizardInfo,
|
||
|
IN LPWSTR *ppwszCSPList)
|
||
|
{
|
||
|
|
||
|
DWORD dwCSPIndex = 0;
|
||
|
DWORD dwGlobalIndex = 0;
|
||
|
LPWSTR pwszCSP = NULL;
|
||
|
|
||
|
//for UI case, there is no CSP checking
|
||
|
if(0 == (CRYPTUI_WIZ_NO_UI & (pCertWizardInfo->dwFlags)))
|
||
|
return TRUE;
|
||
|
|
||
|
//if the csp list is specfied, we are OK
|
||
|
if(pCertWizardInfo->pwszProvider)
|
||
|
return TRUE;
|
||
|
|
||
|
if(NULL==ppwszCSPList)
|
||
|
return FALSE;
|
||
|
|
||
|
for(dwGlobalIndex=0; dwGlobalIndex < pCertWizardInfo->dwCSPCount; dwGlobalIndex++)
|
||
|
{
|
||
|
// Loop over the NULL-terminated CSP array...
|
||
|
for (pwszCSP = ppwszCSPList[dwCSPIndex = 0]; NULL != pwszCSP; pwszCSP = ppwszCSPList[dwCSPIndex++])
|
||
|
{
|
||
|
if(0==_wcsicmp(pCertWizardInfo->rgwszProvider[dwGlobalIndex], pwszCSP))
|
||
|
{
|
||
|
// A match!
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Didn't find a CSP match.
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
// CheckCSPRequirement
|
||
|
//
|
||
|
//--------------------------------------------------------------------
|
||
|
BOOL CheckCSPRequirement(IN HCERTTYPE hCurCertType,
|
||
|
IN CERT_WIZARD_INFO *pCertWizardInfo)
|
||
|
{
|
||
|
BOOL fSupported = FALSE;
|
||
|
HRESULT hr;
|
||
|
LPWSTR *ppwszCSPList = NULL;
|
||
|
|
||
|
if (NULL == hCurCertType)
|
||
|
return FALSE;
|
||
|
|
||
|
//get the CSP list from the cert type
|
||
|
hr = CAGetCertTypeProperty
|
||
|
(hCurCertType,
|
||
|
CERTTYPE_PROP_CSP_LIST,
|
||
|
&ppwszCSPList);
|
||
|
if (S_OK == hr)
|
||
|
{
|
||
|
if (NULL != ppwszCSPList)
|
||
|
{
|
||
|
// The template specifies a CSP list. See if we can support it.
|
||
|
fSupported = CheckCertTypeCSP(pCertWizardInfo, ppwszCSPList);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Any CSP is good. Just make sure we have one:
|
||
|
fSupported = 0 != pCertWizardInfo->dwCSPCount;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Can't get the CSP list. For UI case, CSP is optional
|
||
|
if(0 == (CRYPTUI_WIZ_NO_UI & (pCertWizardInfo->dwFlags)))
|
||
|
fSupported = TRUE;
|
||
|
else
|
||
|
//for UILess case, if a CSP is selected, it is also OK
|
||
|
fSupported = NULL != pCertWizardInfo->pwszProvider;
|
||
|
}
|
||
|
|
||
|
//free the properties
|
||
|
if(NULL != ppwszCSPList) { CAFreeCertTypeProperty(hCurCertType, ppwszCSPList); }
|
||
|
|
||
|
// All done.
|
||
|
return fSupported;
|
||
|
}
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
// Make sure that the CA supports at least one valid cert type
|
||
|
//
|
||
|
//--------------------------------------------------------------------
|
||
|
BOOL IsValidCA(IN CERT_WIZARD_INFO *pCertWizardInfo,
|
||
|
IN PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo,
|
||
|
IN HCAINFO hCAInfo)
|
||
|
{
|
||
|
BOOL fSupported = FALSE;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
CertDSManager *pDSManager = NULL;
|
||
|
HCERTTYPE hCurCertType = NULL;
|
||
|
HCERTTYPE hPreCertType = NULL;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
|
||
|
__try {
|
||
|
_JumpCondition(NULL == hCAInfo || NULL == pCertWizardInfo || NULL == pCertWizardInfo->hRequester, InvalidArgError);
|
||
|
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
pDSManager = pCertRequester->GetDSManager();
|
||
|
_JumpCondition(NULL == pDSManager, InvalidArgError);
|
||
|
|
||
|
if (S_OK != (hr = pDSManager->EnumCertTypesForCA
|
||
|
(hCAInfo,
|
||
|
(pCertWizardInfo->fMachine ? CT_ENUM_MACHINE_TYPES | CT_FIND_LOCAL_SYSTEM : CT_ENUM_USER_TYPES),
|
||
|
&hCurCertType)))
|
||
|
goto CLEANUP;
|
||
|
|
||
|
while (NULL != hCurCertType)
|
||
|
{
|
||
|
//make sure the principal making this call has access to request
|
||
|
//this cert type, even if he's requesting on behalf of another.
|
||
|
fSupported = CAUtilValidCertTypeNoDS
|
||
|
(hCurCertType,
|
||
|
pCertRequestInfo->pwszCertDNName,
|
||
|
pCertWizardInfo);
|
||
|
|
||
|
// We've found a cert type which we can use for enrollment -- this CA is valid.
|
||
|
_JumpCondition(TRUE == fSupported, CLEANUP);
|
||
|
|
||
|
//enum for the next cert types
|
||
|
hPreCertType = hCurCertType;
|
||
|
|
||
|
hr = pDSManager->EnumNextCertType
|
||
|
(hPreCertType,
|
||
|
&hCurCertType);
|
||
|
_JumpCondition(S_OK != hr, CLEANUP);
|
||
|
|
||
|
//free the old cert type
|
||
|
pDSManager->CloseCertType(hPreCertType);
|
||
|
hPreCertType = NULL;
|
||
|
}
|
||
|
|
||
|
ErrorReturn:
|
||
|
CLEANUP:
|
||
|
if(NULL != hCurCertType) { CACloseCertType(hCurCertType); }
|
||
|
if(NULL != hPreCertType) { CACloseCertType(hPreCertType); }
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR(InvalidArgError, E_INVALIDARG);
|
||
|
|
||
|
CommonReturn:;
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(GetExceptionCode());
|
||
|
fSupported = FALSE;
|
||
|
}
|
||
|
|
||
|
return fSupported;
|
||
|
}
|
||
|
|
||
|
BOOL CAUtilGetCertTypeNameNoDS(IN HCERTTYPE hCertType,
|
||
|
OUT LPWSTR *ppwszCTName)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
HRESULT hr;
|
||
|
LPWSTR *ppwszNameProp = NULL;
|
||
|
|
||
|
_JumpCondition(NULL == hCertType || NULL == ppwszCTName, InvalidArgErr);
|
||
|
|
||
|
// Init input params:
|
||
|
*ppwszCTName = NULL;
|
||
|
|
||
|
//get the machine readable form
|
||
|
hr = CAGetCertTypePropertyEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_PROP_DN,
|
||
|
&ppwszNameProp);
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszNameProp, CertCliErr, S_OK == hr ? hr = E_FAIL : hr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszNameProp[0], CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
*ppwszCTName = WizardAllocAndCopyWStr(ppwszNameProp[0]);
|
||
|
_JumpCondition(NULL==(*ppwszCTName), MemoryErr);
|
||
|
|
||
|
fResult = TRUE;
|
||
|
CommonReturn:
|
||
|
if(NULL != ppwszNameProp) { CAFreeCAProperty(hCertType, ppwszNameProp); }
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
if (NULL != ppwszCTName && NULL != *ppwszCTName) { WizardFree(*ppwszCTName); }
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
|
||
|
SET_ERROR(InvalidArgErr, E_INVALIDARG);
|
||
|
SET_ERROR_VAR(CertCliErr, hr);
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
//From the API's cert type name, get the real machine readable name
|
||
|
//
|
||
|
//---------------------------------------------------------------------
|
||
|
BOOL CAUtilGetCertTypeName(CERT_WIZARD_INFO *pCertWizardInfo,
|
||
|
LPWSTR pwszAPIName,
|
||
|
LPWSTR *ppwszCTName)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
CertDSManager *pDSManager = NULL;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
DWORD dwException = 0;
|
||
|
HCERTTYPE hCertType = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
LPWSTR *ppwszNameProp = NULL;
|
||
|
|
||
|
_JumpCondition(NULL == pCertWizardInfo || NULL == pCertWizardInfo->hRequester, InvalidArgError);
|
||
|
|
||
|
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
pDSManager = pCertRequester->GetDSManager();
|
||
|
_JumpCondition(NULL == pDSManager, InvalidArgError);
|
||
|
|
||
|
__try {
|
||
|
|
||
|
//get the handle based on name
|
||
|
hr= pDSManager->FindCertTypeByName
|
||
|
(pwszAPIName,
|
||
|
NULL,
|
||
|
(pCertWizardInfo->fMachine?CT_ENUM_MACHINE_TYPES|CT_FIND_LOCAL_SYSTEM:CT_ENUM_USER_TYPES),
|
||
|
&hCertType);
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == hCertType, CertCliErr, S_OK == hr ? hr = E_FAIL : hr);
|
||
|
|
||
|
fResult = CAUtilGetCertTypeNameNoDS(hCertType, ppwszCTName);
|
||
|
_JumpConditionWithExpr(FALSE == fResult, CertCliErr, hr = GetLastError());
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
dwException = GetExceptionCode();
|
||
|
goto ExceptionErr;
|
||
|
}
|
||
|
|
||
|
fResult = TRUE;
|
||
|
|
||
|
CommonReturn:
|
||
|
//free the memory
|
||
|
__try{
|
||
|
if(NULL != hCertType) { pDSManager->CloseCertType(hCertType); }
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
fResult = FALSE;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR_VAR(CertCliErr, hr);
|
||
|
SET_ERROR_VAR(ExceptionErr, dwException);
|
||
|
SET_ERROR_VAR(InvalidArgError, E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL CAUtilValidCertTypeNoDS(HCERTTYPE hCertType,
|
||
|
LPWSTR pwszCertDNName,
|
||
|
CERT_WIZARD_INFO *pCertWizardInfo)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
CertRequesterContext *pCertRequesterContext = NULL;
|
||
|
|
||
|
_JumpCondition(hCertType == NULL || pCertWizardInfo == NULL || NULL == pCertWizardInfo->hRequester, InvalidArgError);
|
||
|
|
||
|
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
pCertRequesterContext = pCertRequester->GetContext();
|
||
|
_JumpCondition(NULL == pCertRequesterContext, InvalidArgError);
|
||
|
|
||
|
//check the subject requirements
|
||
|
_JumpCondition(FALSE == CheckSubjectRequirement(hCertType, pwszCertDNName), InvalidArgError);
|
||
|
|
||
|
//check for the permission of the cert type
|
||
|
_JumpCondition(FALSE == pCertRequesterContext->CheckAccessPermission(hCertType), AccessDeniedError);
|
||
|
|
||
|
//check for the CSP permission of the cert type
|
||
|
_JumpCondition(FALSE == CheckCSPRequirement(hCertType, pCertWizardInfo), InvalidArgError);
|
||
|
|
||
|
fResult = TRUE;
|
||
|
|
||
|
CommonReturn:
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
fResult = FALSE;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR_VAR(AccessDeniedError, E_ACCESSDENIED);
|
||
|
SET_ERROR_VAR(InvalidArgError, E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
// Verify that the user has the correct permision to
|
||
|
// ask for the requested certificatd types
|
||
|
//
|
||
|
//--------------------------------------------------------------------
|
||
|
BOOL CAUtilValidCertType(IN PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo,
|
||
|
IN CERT_WIZARD_INFO *pCertWizardInfo)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
CertDSManager *pDSManager = NULL;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
DWORD dwException = 0;
|
||
|
DWORD dwCertTypeIndex = 0;
|
||
|
HCERTTYPE hCertType = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
PCCRYPTUI_WIZ_CERT_TYPE pCertType = NULL;
|
||
|
|
||
|
_JumpCondition(NULL == pCertWizardInfo || NULL == pCertWizardInfo->hRequester, InvalidArgError);
|
||
|
|
||
|
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
pDSManager = pCertRequester->GetDSManager();
|
||
|
_JumpCondition(NULL == pDSManager, InvalidArgError);
|
||
|
|
||
|
__try {
|
||
|
|
||
|
//enum all the cert types. For each of them,
|
||
|
//1. Has the correct permission
|
||
|
//2. Has the correct subject requirement
|
||
|
if(NULL != pCertRequestInfo)
|
||
|
{
|
||
|
if(CRYPTUI_WIZ_CERT_REQUEST_CERT_TYPE == pCertRequestInfo->dwCertChoice)
|
||
|
{
|
||
|
pCertType = pCertRequestInfo->pCertType;
|
||
|
|
||
|
for(dwCertTypeIndex=0; dwCertTypeIndex <pCertType->cCertType; dwCertTypeIndex++)
|
||
|
{
|
||
|
DWORD dwFlags = CT_FIND_BY_OID;
|
||
|
dwFlags |= pCertWizardInfo->fMachine ? CT_ENUM_MACHINE_TYPES | CT_FIND_LOCAL_SYSTEM : CT_ENUM_USER_TYPES;
|
||
|
|
||
|
//get the handle based on OID
|
||
|
hr= pDSManager->FindCertTypeByName
|
||
|
(pCertType->rgwszCertType[dwCertTypeIndex],
|
||
|
NULL,
|
||
|
dwFlags,
|
||
|
&hCertType);
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
// get the handle based on name:
|
||
|
dwFlags &= ~CT_FIND_BY_OID;
|
||
|
hr = pDSManager->FindCertTypeByName
|
||
|
(pCertType->rgwszCertType[dwCertTypeIndex],
|
||
|
NULL,
|
||
|
dwFlags,
|
||
|
&hCertType);
|
||
|
}
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == hCertType, CertCliErr, hr == S_OK ? hr = E_FAIL : hr);
|
||
|
|
||
|
if (!CAUtilValidCertTypeNoDS(hCertType, pCertRequestInfo->pwszCertDNName, pCertWizardInfo))
|
||
|
{
|
||
|
hr = GetLastError();
|
||
|
goto CertCliErr;
|
||
|
}
|
||
|
|
||
|
//free the cert type
|
||
|
if(NULL != hCertType)
|
||
|
{
|
||
|
pDSManager->CloseCertType(hCertType);
|
||
|
hCertType = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
dwException = GetExceptionCode();
|
||
|
goto ExceptionErr;
|
||
|
}
|
||
|
|
||
|
fResult = TRUE;
|
||
|
|
||
|
CommonReturn:
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
__try {
|
||
|
if(NULL != hCertType) { pDSManager->CloseCertType(hCertType); }
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
fResult = FALSE;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR_VAR(CertCliErr, hr);
|
||
|
SET_ERROR_VAR(ExceptionErr, dwException)
|
||
|
SET_ERROR_VAR(InvalidArgError, E_INVALIDARG);
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
//Retrieve a list of CAs that supports at least one valid cert types
|
||
|
//
|
||
|
//---------------------------------------------------------------------
|
||
|
BOOL CAUtilRetrieveCAFromCertType(
|
||
|
CERT_WIZARD_INFO *pCertWizardInfo,
|
||
|
PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo,
|
||
|
BOOL fMultipleCA, //only need one CA
|
||
|
DWORD dwNameFlag,
|
||
|
DWORD *pdwCACount,
|
||
|
LPWSTR **ppwszCALocation,
|
||
|
LPWSTR **ppwszCAName)
|
||
|
{
|
||
|
BOOL fResult=FALSE;
|
||
|
CertDSManager *pDSManager=NULL;
|
||
|
CertRequesterContext *pCertRequesterContext = NULL;
|
||
|
DWORD dwCACount=0;
|
||
|
DWORD dwValidCACount=0;
|
||
|
DWORD dwCAIndex=0;
|
||
|
HRESULT hr=E_FAIL;
|
||
|
|
||
|
HCAINFO hCurCAInfo=NULL;
|
||
|
HCAINFO hPreCAInfo=NULL;
|
||
|
LPWSTR *ppwszNameProp=NULL;
|
||
|
LPWSTR *ppwszLocationProp=NULL;
|
||
|
|
||
|
LPWSTR pwszDNName=NULL;
|
||
|
PCCERT_CONTEXT pCertContext=NULL;
|
||
|
DWORD dwSize=0;
|
||
|
DWORD dwException=0;
|
||
|
|
||
|
|
||
|
//input param checking
|
||
|
if(!pdwCACount || !ppwszCALocation || !ppwszCAName)
|
||
|
return E_INVALIDARG;
|
||
|
|
||
|
//init
|
||
|
*pdwCACount=0;
|
||
|
*ppwszCALocation=NULL;
|
||
|
*ppwszCAName=NULL;
|
||
|
|
||
|
__try {
|
||
|
|
||
|
//get a CA from the DS
|
||
|
if(NULL != pCertWizardInfo)
|
||
|
{
|
||
|
CertRequester * pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
_JumpCondition(NULL == pCertRequester, InvalidArgErr);
|
||
|
|
||
|
pCertRequesterContext = pCertRequester->GetContext();
|
||
|
_JumpCondition(NULL == pCertRequesterContext, InvalidArgErr);
|
||
|
|
||
|
pDSManager = pCertRequester->GetDSManager();
|
||
|
_JumpCondition(NULL == pDSManager, InvalidArgErr);
|
||
|
|
||
|
hr=pDSManager->EnumFirstCA(
|
||
|
NULL,
|
||
|
(pCertWizardInfo->fMachine?CA_FIND_LOCAL_SYSTEM:0),
|
||
|
&hCurCAInfo);
|
||
|
_JumpCondition(S_OK != hr, CAEnumCAErr);
|
||
|
_JumpCondition(NULL == hCurCAInfo, CAEnumCAErrNotFound);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//this is for SelCA API where pCertWizardInfo is NULL
|
||
|
hr = CAEnumFirstCA
|
||
|
(NULL,
|
||
|
(CRYPTUI_DLG_SELECT_CA_LOCAL_MACHINE_ENUMERATION & dwNameFlag) ? CA_FIND_LOCAL_SYSTEM:0,
|
||
|
&hCurCAInfo);
|
||
|
_JumpCondition(S_OK != hr, CAEnumCAErr);
|
||
|
_JumpCondition(NULL == hCurCAInfo, CAEnumCAErrNotFound);
|
||
|
|
||
|
if (S_OK != CertRequesterContext::MakeDefaultCertRequesterContext(&pCertRequesterContext))
|
||
|
goto UnexpectedErr;
|
||
|
}
|
||
|
|
||
|
//get the CA count
|
||
|
dwCACount = CACountCAs(hCurCAInfo);
|
||
|
_JumpConditionWithExpr(0 == dwCACount, CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
//memory allocation and memset
|
||
|
*ppwszCALocation=(LPWSTR *)WizardAlloc(sizeof(LPWSTR) * dwCACount);
|
||
|
_JumpCondition(NULL == *ppwszCALocation, MemoryErr);
|
||
|
memset(*ppwszCALocation, 0, sizeof(LPWSTR) * dwCACount);
|
||
|
|
||
|
*ppwszCAName=(LPWSTR *)WizardAlloc(sizeof(LPWSTR) * dwCACount);
|
||
|
_JumpCondition(NULL == *ppwszCAName, MemoryErr);
|
||
|
memset(*ppwszCAName, 0, sizeof(LPWSTR) * dwCACount);
|
||
|
|
||
|
dwValidCACount = 0;
|
||
|
|
||
|
//enum all the CAs available on the DS
|
||
|
for(dwCAIndex = 0; dwCAIndex < dwCACount; dwCAIndex++)
|
||
|
{
|
||
|
//make sure the CA supports all the cert types
|
||
|
if(NULL != pCertRequestInfo)
|
||
|
{
|
||
|
// Skip this CA if it is not valid.
|
||
|
_JumpCondition(FALSE == IsValidCA(pCertWizardInfo, pCertRequestInfo, hCurCAInfo), next);
|
||
|
}
|
||
|
|
||
|
// Skip this CA if the user does not have access rights to it.
|
||
|
_JumpCondition(FALSE == pCertRequesterContext->CheckCAPermission(hCurCAInfo), next);
|
||
|
|
||
|
//copy the CA name and location
|
||
|
|
||
|
//get the CA's CN or DN based on dwNameFlag
|
||
|
if(CRYPTUI_DLG_SELECT_CA_USE_DN & dwNameFlag)
|
||
|
{
|
||
|
//get the CA's certificate
|
||
|
hr = CAGetCACertificate(hCurCAInfo, &pCertContext);
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL==pCertContext, CertCliErr, S_OK == hr ? hr = E_FAIL : hr);
|
||
|
|
||
|
//get the DN name
|
||
|
dwSize = CertNameToStrW(pCertContext->dwCertEncodingType,
|
||
|
&(pCertContext->pCertInfo->Subject),
|
||
|
CERT_X500_NAME_STR,
|
||
|
NULL,
|
||
|
0);
|
||
|
|
||
|
_JumpCondition(0 == dwSize, TraceErr);
|
||
|
|
||
|
pwszDNName=(LPWSTR)WizardAlloc(dwSize * sizeof(WCHAR));
|
||
|
_JumpCondition(NULL==pwszDNName, MemoryErr);
|
||
|
|
||
|
dwSize = CertNameToStrW(pCertContext->dwCertEncodingType,
|
||
|
&(pCertContext->pCertInfo->Subject),
|
||
|
CERT_X500_NAME_STR,
|
||
|
pwszDNName,
|
||
|
dwSize);
|
||
|
|
||
|
_JumpCondition(0==dwSize, TraceErr);
|
||
|
|
||
|
//copy the name
|
||
|
(*ppwszCAName)[dwValidCACount]=WizardAllocAndCopyWStr(pwszDNName);
|
||
|
_JumpCondition(NULL==(*ppwszCAName)[dwValidCACount], TraceErr);
|
||
|
|
||
|
WizardFree(pwszDNName);
|
||
|
pwszDNName = NULL;
|
||
|
|
||
|
CertFreeCertificateContext(pCertContext);
|
||
|
pCertContext = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hr = CAGetCAProperty(
|
||
|
hCurCAInfo,
|
||
|
CA_PROP_NAME,
|
||
|
&ppwszNameProp);
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszNameProp, CertCliErr, S_OK == hr ? hr = E_FAIL : hr);
|
||
|
|
||
|
//copy the name
|
||
|
(*ppwszCAName)[dwValidCACount] = WizardAllocAndCopyWStr(ppwszNameProp[0]);
|
||
|
_JumpCondition(NULL == (*ppwszCAName)[dwValidCACount], TraceErr);
|
||
|
|
||
|
//free the property
|
||
|
CAFreeCAProperty(hCurCAInfo, ppwszNameProp);
|
||
|
ppwszNameProp = NULL;
|
||
|
}
|
||
|
|
||
|
//get the location
|
||
|
hr = CAGetCAProperty
|
||
|
(hCurCAInfo,
|
||
|
CA_PROP_DNSNAME,
|
||
|
&ppwszLocationProp);
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszLocationProp, CertCliErr, S_OK == hr ? hr = E_FAIL : hr);
|
||
|
|
||
|
//copy the name
|
||
|
(*ppwszCALocation)[dwValidCACount]=WizardAllocAndCopyWStr(ppwszLocationProp[0]);
|
||
|
_JumpCondition(NULL == (*ppwszCALocation)[dwValidCACount], TraceErr);
|
||
|
|
||
|
//free the property
|
||
|
CAFreeCAProperty(hCurCAInfo, ppwszLocationProp);
|
||
|
ppwszLocationProp = NULL;
|
||
|
|
||
|
//increment the count
|
||
|
dwValidCACount++;
|
||
|
|
||
|
next:
|
||
|
//enum for the CA
|
||
|
hPreCAInfo = hCurCAInfo;
|
||
|
|
||
|
hr = CAEnumNextCA
|
||
|
(hPreCAInfo,
|
||
|
&hCurCAInfo);
|
||
|
|
||
|
//free the old CA Info
|
||
|
CACloseCA(hPreCAInfo);
|
||
|
hPreCAInfo=NULL;
|
||
|
|
||
|
if((S_OK != hr) || (NULL==hCurCAInfo))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*pdwCACount = dwValidCACount;
|
||
|
_JumpConditionWithExpr(0 == (*pdwCACount), CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
dwException = GetExceptionCode();
|
||
|
goto ExceptionErr;
|
||
|
}
|
||
|
|
||
|
fResult = TRUE;
|
||
|
|
||
|
CommonReturn:
|
||
|
|
||
|
//free memory
|
||
|
__try {
|
||
|
if(NULL != ppwszNameProp) { CAFreeCAProperty(hCurCAInfo, ppwszNameProp); }
|
||
|
if(NULL != ppwszLocationProp) { CAFreeCAProperty(hCurCAInfo, ppwszLocationProp); }
|
||
|
if(NULL != hPreCAInfo) { CACloseCA(hPreCAInfo); }
|
||
|
if(NULL != hCurCAInfo) { CACloseCA(hCurCAInfo); }
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
if(NULL != pwszDNName) { WizardFree(pwszDNName); }
|
||
|
if(NULL != pCertContext) { CertFreeCertificateContext(pCertContext); }
|
||
|
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
|
||
|
//free the memory in failure case
|
||
|
if(NULL != ppwszCALocation && NULL != *ppwszCALocation)
|
||
|
{
|
||
|
for(dwCAIndex=0; dwCAIndex < dwCACount; dwCAIndex++)
|
||
|
{
|
||
|
if(NULL != (*ppwszCALocation)[dwCAIndex]) { WizardFree((*ppwszCALocation)[dwCAIndex]); }
|
||
|
}
|
||
|
|
||
|
WizardFree(*ppwszCALocation);
|
||
|
*ppwszCALocation = NULL;
|
||
|
}
|
||
|
|
||
|
if(NULL != ppwszCAName && NULL != *ppwszCAName)
|
||
|
{
|
||
|
for(dwCAIndex=0; dwCAIndex < dwCACount; dwCAIndex++)
|
||
|
{
|
||
|
if(NULL != (*ppwszCAName)[dwCAIndex]) { WizardFree((*ppwszCAName)[dwCAIndex]); }
|
||
|
}
|
||
|
|
||
|
WizardFree(*ppwszCAName);
|
||
|
*ppwszCAName = NULL;
|
||
|
}
|
||
|
|
||
|
fResult = FALSE;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR(InvalidArgErr, E_INVALIDARG);
|
||
|
SET_ERROR_VAR(CertCliErr, hr);
|
||
|
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
|
||
|
TRACE_ERROR(TraceErr);
|
||
|
SET_ERROR_VAR(CAEnumCAErr, hr);
|
||
|
SET_ERROR(CAEnumCAErrNotFound, ERROR_DS_OBJ_NOT_FOUND);
|
||
|
SET_ERROR_VAR(ExceptionErr, dwException)
|
||
|
SET_ERROR(UnexpectedErr, E_UNEXPECTED);
|
||
|
}
|
||
|
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
//Based on the CA name and CA location, get a list of certificate type
|
||
|
//and their extensions
|
||
|
//
|
||
|
// 1. Check the permission of the cert types
|
||
|
// 2. Check the subject requirement of the cert types
|
||
|
//---------------------------------------------------------------------
|
||
|
|
||
|
BOOL CAUtilGetCertTypeNameAndExtensionsNoDS
|
||
|
(
|
||
|
CERT_WIZARD_INFO *pCertWizardInfo,
|
||
|
LPWSTR pwszCertDNName,
|
||
|
HCERTTYPE hCertType,
|
||
|
LPWSTR *ppwszCertType,
|
||
|
LPWSTR *ppwszDisplayCertType,
|
||
|
PCERT_EXTENSIONS *pCertExtensions,
|
||
|
DWORD *pdwKeySpec,
|
||
|
DWORD *pdwMinKeySize,
|
||
|
DWORD *pdwCSPCount,
|
||
|
DWORD **ppdwCSPList,
|
||
|
DWORD *pdwRASignature,
|
||
|
DWORD *pdwEnrollmentFlags,
|
||
|
DWORD *pdwSubjectNameFlags,
|
||
|
DWORD *pdwPrivateKeyFlags,
|
||
|
DWORD *pdwGeneralFlags)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
CertRequesterContext *pCertRequesterContext = NULL;
|
||
|
DWORD dwGlobalIndex = 0;
|
||
|
DWORD dwLastError = ERROR_SUCCESS;
|
||
|
DWORD dwCSPIndex = 0;
|
||
|
DWORD dwFlags = 0;
|
||
|
DWORD dwKeySpec = 0;
|
||
|
DWORD dwEnrollmentFlags;
|
||
|
DWORD dwSubjectNameFlags;
|
||
|
DWORD dwPrivateKeyFlags;
|
||
|
DWORD dwGeneralFlags;
|
||
|
DWORD dwSchemaVersion;
|
||
|
HRESULT hr = S_OK;
|
||
|
LPWSTR pwszCSP = NULL;
|
||
|
LPWSTR *ppwszCSP = NULL;
|
||
|
LPWSTR *ppwszDisplayCertTypeName = NULL;
|
||
|
LPWSTR *ppwszCertTypeName = NULL;
|
||
|
|
||
|
// Input validation:
|
||
|
if (NULL == pCertWizardInfo || NULL == pCertWizardInfo->hRequester ||
|
||
|
NULL == ppwszCertType || NULL == ppwszDisplayCertType ||
|
||
|
NULL == pCertExtensions || NULL == pdwKeySpec ||
|
||
|
NULL == pdwMinKeySize || NULL == pdwCSPCount ||
|
||
|
NULL == ppdwCSPList || NULL == pdwRASignature ||
|
||
|
NULL == pdwEnrollmentFlags || NULL == pdwSubjectNameFlags ||
|
||
|
NULL == pdwPrivateKeyFlags || NULL == pdwGeneralFlags)
|
||
|
{
|
||
|
SetLastError(E_INVALIDARG);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Init:
|
||
|
*ppwszDisplayCertType = NULL;
|
||
|
*ppwszCertType = NULL;
|
||
|
*pCertExtensions = NULL;
|
||
|
*pdwKeySpec = NULL;
|
||
|
*pdwMinKeySize = NULL;
|
||
|
*pdwCSPCount = NULL;
|
||
|
*ppdwCSPList = NULL;
|
||
|
*pdwRASignature = NULL;
|
||
|
*pdwEnrollmentFlags = NULL;
|
||
|
*pdwSubjectNameFlags = NULL;
|
||
|
*pdwPrivateKeyFlags = NULL;
|
||
|
*pdwGeneralFlags = NULL;
|
||
|
|
||
|
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
pCertRequesterContext = pCertRequester->GetContext();
|
||
|
_JumpCondition(NULL == pCertRequesterContext, InvalidArgError);
|
||
|
|
||
|
// check the subject requirement of the cert type
|
||
|
_JumpCondition(!CheckSubjectRequirement(hCertType,pwszCertDNName), CommonReturn);
|
||
|
|
||
|
//check for the key specification of the cert type
|
||
|
//we do not care about the return value. Since it will be set to 0
|
||
|
//if the function failed.
|
||
|
CAGetCertTypeKeySpec(hCertType, &dwKeySpec);
|
||
|
|
||
|
//check for the CSP requirement of the cert type
|
||
|
if((S_OK ==(hr=CAGetCertTypeProperty(hCertType,
|
||
|
CERTTYPE_PROP_CSP_LIST,
|
||
|
&ppwszCSP)))&&
|
||
|
(NULL!=ppwszCSP)
|
||
|
)
|
||
|
{
|
||
|
_JumpCondition(!CheckCertTypeCSP(pCertWizardInfo, ppwszCSP), CommonReturn);
|
||
|
}
|
||
|
|
||
|
//check for the permission of the cert type
|
||
|
_JumpCondition(FALSE == pCertRequesterContext->CheckAccessPermission(hCertType), CommonReturn);
|
||
|
|
||
|
//now, we have found a valid cert type.
|
||
|
//copy Display name, extension, key spec, dwCertTypeFlag,
|
||
|
//the CSP list
|
||
|
|
||
|
//
|
||
|
// First, get all applicable cert type flags:
|
||
|
//
|
||
|
|
||
|
// Get enrollment flags:
|
||
|
if (S_OK != (hr=CAGetCertTypeFlagsEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_ENROLLMENT_FLAG,
|
||
|
&dwEnrollmentFlags)))
|
||
|
goto CertCliErr;
|
||
|
|
||
|
// Get subject name flags:
|
||
|
if (S_OK != (hr=CAGetCertTypeFlagsEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_SUBJECT_NAME_FLAG,
|
||
|
&dwSubjectNameFlags)))
|
||
|
goto CertCliErr;
|
||
|
|
||
|
// Get private key flags.
|
||
|
if(S_OK != (hr = CAGetCertTypeFlagsEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_PRIVATE_KEY_FLAG,
|
||
|
&dwPrivateKeyFlags)))
|
||
|
goto CertCliErr;
|
||
|
|
||
|
// Get general flags:
|
||
|
if (S_OK != (hr=CAGetCertTypeFlagsEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_GENERAL_FLAG,
|
||
|
&dwGeneralFlags)))
|
||
|
goto CertCliErr;
|
||
|
|
||
|
// Filter out CT where subject name or subject alt name must be supplied.
|
||
|
if (dwSubjectNameFlags &
|
||
|
(CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT |
|
||
|
CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT_ALT_NAME
|
||
|
))
|
||
|
goto CommonReturn;
|
||
|
|
||
|
*pdwEnrollmentFlags = dwEnrollmentFlags;
|
||
|
*pdwSubjectNameFlags = dwSubjectNameFlags;
|
||
|
*pdwPrivateKeyFlags = dwPrivateKeyFlags;
|
||
|
*pdwGeneralFlags = dwGeneralFlags;
|
||
|
|
||
|
|
||
|
//get the display name of the cert type
|
||
|
hr = CAGetCertTypeProperty
|
||
|
(hCertType,
|
||
|
CERTTYPE_PROP_FRIENDLY_NAME,
|
||
|
&ppwszDisplayCertTypeName);
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszDisplayCertTypeName, CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
//copy the name
|
||
|
*ppwszDisplayCertType = WizardAllocAndCopyWStr(ppwszDisplayCertTypeName[0]);
|
||
|
_JumpCondition(NULL == *ppwszDisplayCertType, MemoryError);
|
||
|
|
||
|
//get the machine readable name of the cert type
|
||
|
hr=CAGetCertTypeProperty
|
||
|
(hCertType,
|
||
|
CERTTYPE_PROP_DN,
|
||
|
&ppwszCertTypeName);
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszCertTypeName, CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
//copy the name
|
||
|
*ppwszCertType = WizardAllocAndCopyWStr(ppwszCertTypeName[0]);
|
||
|
_JumpCondition(NULL == *ppwszCertType, TraceError);
|
||
|
|
||
|
//copy the dwKeySpec
|
||
|
*pdwKeySpec = dwKeySpec;
|
||
|
|
||
|
//
|
||
|
// Assign V2 Properties.
|
||
|
// If the current cert type is a V1 cert type, use default values.
|
||
|
// Otherwise, get the properties from the CA.
|
||
|
//
|
||
|
if (S_OK != (hr=CAGetCertTypePropertyEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_PROP_SCHEMA_VERSION,
|
||
|
&dwSchemaVersion)))
|
||
|
goto CertCliErr;
|
||
|
|
||
|
if (dwSchemaVersion == CERTTYPE_SCHEMA_VERSION_1)
|
||
|
{
|
||
|
// NULL out the left half-word. This indicates that the min
|
||
|
// key size is not specified, and should be defaulted during
|
||
|
// enrollment.
|
||
|
*pdwMinKeySize = 0;
|
||
|
// Set requird number of required RA signatures to 0 (default).
|
||
|
*pdwRASignature = 0;
|
||
|
}
|
||
|
else if (dwSchemaVersion == CERTTYPE_SCHEMA_VERSION_2)
|
||
|
{
|
||
|
// Get the minimum key size from the CA
|
||
|
if (S_OK != (hr=CAGetCertTypePropertyEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_PROP_MIN_KEY_SIZE,
|
||
|
&dwFlags)))
|
||
|
goto CertCliErr;
|
||
|
|
||
|
// Copy the minimum key size. The minimum key size is stored in the
|
||
|
// top half-word of the type flags.
|
||
|
*pdwMinKeySize |= dwFlags;
|
||
|
|
||
|
// Get the number of required RA signatures from the CA
|
||
|
if (S_OK != (hr=CAGetCertTypePropertyEx
|
||
|
(hCertType,
|
||
|
CERTTYPE_PROP_RA_SIGNATURE,
|
||
|
pdwRASignature)))
|
||
|
goto CertCliErr;
|
||
|
}
|
||
|
|
||
|
// Filter out CTs which require RA signatures.
|
||
|
if (*pdwRASignature > 0)
|
||
|
{
|
||
|
if (0 != (CRYPTUI_WIZ_NO_UI & pCertWizardInfo->dwFlags))
|
||
|
{
|
||
|
// In the no-UI case, we assume that the caller knows what they
|
||
|
// are doing.
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ((0 != (CRYPTUI_WIZ_CERT_RENEW & pCertWizardInfo->dwPurpose)) &&
|
||
|
(0 != (CT_FLAG_PREVIOUS_APPROVAL_VALIDATE_REENROLLMENT & dwEnrollmentFlags)))
|
||
|
{
|
||
|
// Special case: we're doing a renew, and the previous approval for this cert
|
||
|
// validates future re-enrollments. We don't _really_ need RA sigs.
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// This CT requires RA signatures. Filter it out:
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// copy the necessary extensions
|
||
|
if (S_OK != (hr = CAGetCertTypeExtensionsEx
|
||
|
(hCertType,
|
||
|
CT_EXTENSION_TEMPLATE,
|
||
|
NULL,
|
||
|
&(*pCertExtensions))))
|
||
|
goto CertCliErr;
|
||
|
|
||
|
//set up the CSP list. It will be a DWORD array index to the
|
||
|
//global CSP list
|
||
|
*ppdwCSPList = (DWORD *)WizardAlloc(sizeof(DWORD) * (pCertWizardInfo->dwCSPCount));
|
||
|
_JumpCondition(NULL == (*ppdwCSPList), MemoryError);
|
||
|
|
||
|
memset((*ppdwCSPList), 0 ,sizeof(DWORD) * (pCertWizardInfo->dwCSPCount));
|
||
|
|
||
|
if (NULL == ppwszCSP || NULL == ppwszCSP[0])
|
||
|
{
|
||
|
// no specified CSPs on the templates means that all are allowed:
|
||
|
for(dwGlobalIndex=0; dwGlobalIndex < pCertWizardInfo->dwCSPCount; dwGlobalIndex++)
|
||
|
{
|
||
|
(*ppdwCSPList)[(*pdwCSPCount)]=dwGlobalIndex;
|
||
|
(*pdwCSPCount)++;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//loop through the CSP list and build the index array
|
||
|
//we should have at least on item in the index array since
|
||
|
//we have checked the certtype before
|
||
|
for (pwszCSP = ppwszCSP[dwCSPIndex = 0]; NULL != pwszCSP; pwszCSP = ppwszCSP[++dwCSPIndex])
|
||
|
{
|
||
|
for(dwGlobalIndex=0; dwGlobalIndex < pCertWizardInfo->dwCSPCount; dwGlobalIndex++)
|
||
|
{
|
||
|
if(0==_wcsicmp(pCertWizardInfo->rgwszProvider[dwGlobalIndex], pwszCSP))
|
||
|
{
|
||
|
(*ppdwCSPList)[(*pdwCSPCount)]=dwGlobalIndex;
|
||
|
(*pdwCSPCount)++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fResult = TRUE;
|
||
|
|
||
|
CommonReturn:
|
||
|
SetLastError(dwLastError);
|
||
|
|
||
|
if (NULL != ppwszCSP) { CAFreeCertTypeProperty(hCertType, ppwszCSP); }
|
||
|
if (NULL != ppwszDisplayCertTypeName) { CAFreeCertTypeProperty(hCertType, ppwszDisplayCertTypeName); }
|
||
|
if (NULL != ppwszCertTypeName) { CAFreeCertTypeProperty(hCertType, ppwszCertTypeName); }
|
||
|
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
dwLastError = hr;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_HRESULT(InvalidArgError, E_INVALIDARG);
|
||
|
SET_HRESULT(MemoryError, E_OUTOFMEMORY);
|
||
|
TRACE_ERROR(CertCliErr);
|
||
|
TRACE_ERROR(TraceError);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
BOOL CAUtilGetCertTypeNameAndExtensions(
|
||
|
CERT_WIZARD_INFO *pCertWizardInfo,
|
||
|
PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo,
|
||
|
LPWSTR pwszCALocation,
|
||
|
LPWSTR pwszCAName,
|
||
|
DWORD *pdwCertType,
|
||
|
LPWSTR **ppwszCertType,
|
||
|
LPWSTR **ppwszDisplayCertType,
|
||
|
PCERT_EXTENSIONS **ppCertExtensions,
|
||
|
DWORD **ppdwKeySpec,
|
||
|
DWORD **ppdwMinKeySize,
|
||
|
DWORD **ppdwCSPCount,
|
||
|
DWORD ***ppdwCSPList,
|
||
|
DWORD **ppdwRASignature,
|
||
|
DWORD **ppdwEnrollmentFlags,
|
||
|
DWORD **ppdwSubjectNameFlags,
|
||
|
DWORD **ppdwPrivateKeyFlags,
|
||
|
DWORD **ppdwGeneralFlags)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
CertDSManager *pDSManager = NULL;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
DWORD dwCertTypeCount = 0;
|
||
|
DWORD dwException = 0;
|
||
|
DWORD dwFlags = 0;
|
||
|
DWORD dwIndex = 0;
|
||
|
DWORD dwKeySpec = 0;
|
||
|
DWORD dwValidCertType = 0;
|
||
|
HCAINFO hCAInfo = NULL;
|
||
|
HCERTTYPE hCurCertType = NULL;
|
||
|
HCERTTYPE hPreCertType = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
LPWSTR *ppwszCertTypeName = NULL;
|
||
|
LPWSTR *ppwszDisplayCertTypeName = NULL;
|
||
|
|
||
|
//
|
||
|
// Construct tables to hold arrays we'll be manipulating.
|
||
|
// These tables are used to allocate the arrays, deallocate the arrays, and dealloate
|
||
|
// the array elements (if necessary).
|
||
|
//
|
||
|
|
||
|
typedef struct _CAUTIL_CERTTYPE_ELEM_ARRAY {
|
||
|
LPVOID *lpvArray;
|
||
|
DWORD dwElemSize;
|
||
|
PDEALLOCATOR pElemDeallocator;
|
||
|
} CAUTIL_CERTTYPE_ELEM_ARRAY;
|
||
|
|
||
|
CAUTIL_CERTTYPE_ELEM_ARRAY certTypeElemArrays[] = {
|
||
|
{ (LPVOID *)ppwszDisplayCertType, sizeof (LPWSTR), WizardFreeLPWSTRArray },
|
||
|
{ (LPVOID *)ppwszCertType, sizeof (LPWSTR), WizardFreeLPWSTRArray },
|
||
|
{ (LPVOID *)ppCertExtensions, sizeof (PCERT_EXTENSIONS), CAFreeCertTypeExtensionsArray },
|
||
|
{ (LPVOID *)ppdwKeySpec, sizeof (DWORD), NULL },
|
||
|
{ (LPVOID *)ppdwMinKeySize, sizeof (DWORD), NULL },
|
||
|
{ (LPVOID *)ppdwCSPCount, sizeof (DWORD), NULL },
|
||
|
{ (LPVOID *)ppdwCSPList, sizeof (DWORD *), WizardFreePDWORDArray },
|
||
|
{ (LPVOID *)ppdwRASignature, sizeof (DWORD), NULL },
|
||
|
{ (LPVOID *)ppdwEnrollmentFlags, sizeof (DWORD), NULL },
|
||
|
{ (LPVOID *)ppdwSubjectNameFlags, sizeof (DWORD), NULL },
|
||
|
{ (LPVOID *)ppdwPrivateKeyFlags, sizeof (DWORD), NULL },
|
||
|
{ (LPVOID *)ppdwGeneralFlags, sizeof (DWORD), NULL }
|
||
|
};
|
||
|
|
||
|
DWORD const dwNumCTElemArrays = sizeof(certTypeElemArrays) / sizeof(certTypeElemArrays[0]);
|
||
|
|
||
|
if (NULL == pCertWizardInfo || NULL == pCertRequestInfo ||
|
||
|
NULL == pwszCALocation || NULL == pwszCAName ||
|
||
|
NULL == pdwCertType)
|
||
|
{
|
||
|
SetLastError(E_INVALIDARG);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
if (NULL == pCertRequester)
|
||
|
{
|
||
|
SetLastError(E_INVALIDARG);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
pDSManager = pCertRequester->GetDSManager();
|
||
|
if (NULL == pDSManager)
|
||
|
{
|
||
|
SetLastError(E_INVALIDARG);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
*pdwCertType = 0;
|
||
|
|
||
|
// Check and initialize the input parameters
|
||
|
for (dwIndex = 0; dwIndex < dwNumCTElemArrays; dwIndex++)
|
||
|
{
|
||
|
if (NULL == certTypeElemArrays[dwIndex].lpvArray)
|
||
|
{
|
||
|
SetLastError(E_INVALIDARG);
|
||
|
return FALSE;
|
||
|
}
|
||
|
*(certTypeElemArrays[dwIndex].lpvArray) = NULL;
|
||
|
}
|
||
|
|
||
|
__try {
|
||
|
|
||
|
//get the CA Info handler
|
||
|
hr= pDSManager->FindCAByName
|
||
|
(pwszCAName,
|
||
|
NULL,
|
||
|
(pCertWizardInfo->fMachine?CA_FIND_LOCAL_SYSTEM:0),
|
||
|
&hCAInfo);
|
||
|
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL==hCAInfo, CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
hr=pDSManager->EnumCertTypesForCA
|
||
|
(hCAInfo,
|
||
|
(pCertWizardInfo->fMachine?CT_ENUM_MACHINE_TYPES | CT_FIND_LOCAL_SYSTEM:CT_ENUM_USER_TYPES),
|
||
|
&hCurCertType);
|
||
|
|
||
|
//the CA has to support some cert types
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == hCurCertType, CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
// Get the count of the cert types supported by this CA.
|
||
|
// We should have at least 1 cert type.
|
||
|
dwCertTypeCount = CACountCertTypes(hCurCertType);
|
||
|
_JumpConditionWithExpr(0 == dwCertTypeCount, CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
// Allocate memory for all arrays we'll be manipulating.
|
||
|
for (dwIndex = 0; dwIndex < dwNumCTElemArrays; dwIndex++)
|
||
|
{
|
||
|
CAUTIL_CERTTYPE_ELEM_ARRAY ctea = certTypeElemArrays[dwIndex];
|
||
|
|
||
|
*(ctea.lpvArray) = NULL;
|
||
|
*(ctea.lpvArray) = WizardAlloc(ctea.dwElemSize * dwCertTypeCount);
|
||
|
_JumpCondition(NULL == *(ctea.lpvArray), MemoryErr);
|
||
|
memset(*(ctea.lpvArray), 0, ctea.dwElemSize * dwCertTypeCount);
|
||
|
}
|
||
|
|
||
|
dwValidCertType=0;
|
||
|
for(dwIndex=0; dwIndex < dwCertTypeCount; dwIndex++)
|
||
|
{
|
||
|
if (!CAUtilGetCertTypeNameAndExtensionsNoDS
|
||
|
(pCertWizardInfo,
|
||
|
pCertRequestInfo->pwszCertDNName,
|
||
|
hCurCertType,
|
||
|
&((*ppwszCertType) [dwValidCertType]),
|
||
|
&((*ppwszDisplayCertType) [dwValidCertType]),
|
||
|
&((*ppCertExtensions) [dwValidCertType]),
|
||
|
&((*ppdwKeySpec) [dwValidCertType]),
|
||
|
&((*ppdwMinKeySize) [dwValidCertType]),
|
||
|
&((*ppdwCSPCount) [dwValidCertType]),
|
||
|
&((*ppdwCSPList) [dwValidCertType]),
|
||
|
&((*ppdwRASignature) [dwValidCertType]),
|
||
|
&((*ppdwEnrollmentFlags) [dwValidCertType]),
|
||
|
&((*ppdwSubjectNameFlags) [dwValidCertType]),
|
||
|
&((*ppdwPrivateKeyFlags) [dwValidCertType]),
|
||
|
&((*ppdwGeneralFlags) [dwValidCertType])))
|
||
|
{
|
||
|
if (ERROR_SUCCESS != GetLastError())
|
||
|
{
|
||
|
hr = HRESULT_FROM_WIN32(GetLastError());
|
||
|
goto ErrorReturn;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
goto next;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dwValidCertType++;
|
||
|
|
||
|
next:
|
||
|
//enum for the next cert types
|
||
|
hPreCertType=hCurCertType;
|
||
|
|
||
|
hr = pDSManager->EnumNextCertType(hPreCertType, &hCurCertType);
|
||
|
|
||
|
//free the old cert type
|
||
|
pDSManager->CloseCertType(hPreCertType);
|
||
|
hPreCertType=NULL;
|
||
|
|
||
|
if((S_OK != hr) || (NULL==hCurCertType))
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//copy the cert type count
|
||
|
*pdwCertType=dwValidCertType;
|
||
|
|
||
|
//have to have some valid cert types
|
||
|
_JumpConditionWithExpr(0 == (*pdwCertType), CertCliErr, hr = E_FAIL);
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
dwException = GetExceptionCode();
|
||
|
goto ExceptionErr;
|
||
|
}
|
||
|
|
||
|
fResult=TRUE;
|
||
|
|
||
|
CommonReturn:
|
||
|
//free memory
|
||
|
__try {
|
||
|
if (NULL != ppwszDisplayCertTypeName) { CAFreeCertTypeProperty(hCurCertType, ppwszDisplayCertTypeName); }
|
||
|
if (NULL != ppwszCertTypeName) { CAFreeCertTypeProperty(hCurCertType, ppwszCertTypeName); }
|
||
|
if (NULL != hPreCertType) { pDSManager->CloseCertType(hPreCertType); }
|
||
|
if (NULL != hCurCertType) { pDSManager->CloseCertType(hCurCertType); }
|
||
|
if (NULL != hCAInfo) { pDSManager->CloseCA(hCAInfo); }
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
//free the memory in failure case
|
||
|
for (dwIndex = 0; dwIndex < dwNumCTElemArrays; dwIndex++)
|
||
|
{
|
||
|
CAUTIL_CERTTYPE_ELEM_ARRAY ctea = certTypeElemArrays[dwIndex];
|
||
|
|
||
|
if (NULL != ctea.lpvArray && NULL != *(ctea.lpvArray))
|
||
|
{
|
||
|
if (NULL != ctea.pElemDeallocator)
|
||
|
{
|
||
|
(ctea.pElemDeallocator)(*(ctea.lpvArray), dwCertTypeCount);
|
||
|
}
|
||
|
WizardFree(*(ctea.lpvArray));
|
||
|
*(ctea.lpvArray) = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fResult = FALSE;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR_VAR(CertCliErr, hr);
|
||
|
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
|
||
|
SET_ERROR_VAR(ExceptionErr, dwException)
|
||
|
}
|
||
|
|
||
|
//--------------------------------------------------------------------
|
||
|
//
|
||
|
//Retrieve the CA information based on a certificate
|
||
|
//
|
||
|
//---------------------------------------------------------------------
|
||
|
BOOL CAUtilRetrieveCAFromCert(IN CERT_WIZARD_INFO *pCertWizardInfo,
|
||
|
IN PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo,
|
||
|
OUT LPWSTR *pwszCALocation,
|
||
|
OUT LPWSTR *pwszCAName)
|
||
|
{
|
||
|
BOOL fResult = FALSE;
|
||
|
CertDSManager *pDSManager = NULL;
|
||
|
CertRequester *pCertRequester = NULL;
|
||
|
DWORD dwException = 0;
|
||
|
HCAINFO hCAInfo = NULL;
|
||
|
HRESULT hr = S_OK;
|
||
|
LPWSTR *ppwszCAName = NULL;
|
||
|
LPWSTR *ppwszCALocation = NULL;
|
||
|
PCERT_INFO pCertInfo = NULL;
|
||
|
|
||
|
_JumpCondition(NULL==pwszCALocation || NULL==pwszCAName || NULL==pCertRequestInfo, InvalidArgErr);
|
||
|
|
||
|
//init
|
||
|
*pwszCALocation = NULL;
|
||
|
*pwszCAName = NULL;
|
||
|
|
||
|
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester;
|
||
|
_JumpCondition(NULL == pCertRequester, InvalidArgErr);
|
||
|
pDSManager = pCertRequester->GetDSManager();
|
||
|
_JumpCondition(NULL == pDSManager, InvalidArgErr);
|
||
|
|
||
|
//get the DN name from the certificate
|
||
|
_JumpCondition(NULL == pCertRequestInfo->pRenewCertContext, InvalidArgErr);
|
||
|
|
||
|
pCertInfo = pCertRequestInfo->pRenewCertContext->pCertInfo;
|
||
|
_JumpCondition(NULL==pCertInfo, InvalidArgErr);
|
||
|
|
||
|
__try {
|
||
|
|
||
|
//get the certificate CA based on the DN
|
||
|
hr=CAFindByIssuerDN
|
||
|
(&(pCertInfo->Issuer),
|
||
|
NULL,
|
||
|
(pCertWizardInfo->fMachine?CA_FIND_LOCAL_SYSTEM:0),
|
||
|
&hCAInfo);
|
||
|
|
||
|
//now that we can not get a certificate based on the DN, we
|
||
|
//just get any CA on the DN
|
||
|
if(hr!= S_OK || hCAInfo==NULL)
|
||
|
{
|
||
|
hr=pDSManager->EnumFirstCA(NULL,
|
||
|
(pCertWizardInfo->fMachine?CA_FIND_LOCAL_SYSTEM:0),
|
||
|
&hCAInfo);
|
||
|
}
|
||
|
|
||
|
_JumpCondition(S_OK != hr || hCAInfo == NULL, CertCliErr);
|
||
|
|
||
|
//get the CA's name and machine name
|
||
|
hr = CAGetCAProperty
|
||
|
(hCAInfo,
|
||
|
CA_PROP_NAME,
|
||
|
&ppwszCAName);
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszCAName, CertCliErr, S_OK == hr ? hr = E_FAIL : hr);
|
||
|
|
||
|
hr=CAGetCAProperty
|
||
|
(hCAInfo,
|
||
|
CA_PROP_DNSNAME,
|
||
|
&ppwszCALocation);
|
||
|
_JumpCondition(S_OK != hr, CertCliErr);
|
||
|
_JumpConditionWithExpr(NULL == ppwszCALocation, CertCliErr, S_OK == hr ? hr = E_FAIL : hr);
|
||
|
|
||
|
//copy the result to the output parameter
|
||
|
*pwszCALocation = WizardAllocAndCopyWStr(ppwszCALocation[0]);
|
||
|
_JumpCondition(NULL == *pwszCALocation, TraceErr);
|
||
|
|
||
|
*pwszCAName = WizardAllocAndCopyWStr(ppwszCAName[0]);
|
||
|
_JumpCondition(NULL == *pwszCAName, TraceErr);
|
||
|
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
dwException = GetExceptionCode();
|
||
|
goto ExceptionErr;
|
||
|
}
|
||
|
|
||
|
fResult=TRUE;
|
||
|
|
||
|
CommonReturn:
|
||
|
|
||
|
//free memory
|
||
|
|
||
|
__try {
|
||
|
if (NULL != ppwszCAName) { CAFreeCAProperty(hCAInfo, ppwszCAName); }
|
||
|
if (NULL != ppwszCALocation) { CAFreeCAProperty(hCAInfo, ppwszCALocation); }
|
||
|
if (NULL != hCAInfo) { CACloseCA(hCAInfo); }
|
||
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
||
|
SetLastError(GetExceptionCode());
|
||
|
}
|
||
|
|
||
|
return fResult;
|
||
|
|
||
|
ErrorReturn:
|
||
|
|
||
|
//free the memory in failure case
|
||
|
if(NULL != pwszCALocation && NULL != *pwszCALocation)
|
||
|
{
|
||
|
WizardFree(*pwszCALocation);
|
||
|
*pwszCALocation=NULL;
|
||
|
}
|
||
|
|
||
|
if(NULL != pwszCAName && NULL != *pwszCAName)
|
||
|
{
|
||
|
WizardFree(*pwszCAName);
|
||
|
*pwszCAName=NULL;
|
||
|
}
|
||
|
|
||
|
fResult = FALSE;
|
||
|
goto CommonReturn;
|
||
|
|
||
|
SET_ERROR(InvalidArgErr, E_INVALIDARG);
|
||
|
SET_ERROR_VAR(CertCliErr, hr);
|
||
|
TRACE_ERROR(TraceErr);
|
||
|
SET_ERROR_VAR(ExceptionErr, dwException)
|
||
|
}
|