Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3221 lines
84 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999
//
// File: enrlhelp.cpp
//
// Contents: Helper functions for smard card enrollment station
//
//----------------------------------------------------------------------------
#define INC_OLE2
#define SECURITY_WIN32 //Or in the sources file -DSECURITY_WIN32
#include "stdafx.h"
#include <windows.h>
#include <wincrypt.h>
#include <oleauto.h>
#include <objbase.h>
#include "security.h"
#include "certca.h"
#include <dbgdef.h>
#include "unicode.h"
#include "scrdenrl.h"
#include "SCrdEnr.h"
#include "xEnroll.h"
#include "enrlhelp.h"
#include "scenum.h"
#include "wzrdpvk.h"
UINT g_cfDsObjectPicker = RegisterClipboardFormat(CFSTR_DSOP_DS_SELECTION_LIST);
//-----------------------------------------------------------------------------
// Memory routines
//
//-----------------------------------------------------------------------------
void*
MIDL_user_allocate(size_t cb)
{
return(SCrdEnrollAlloc(cb));
}
void
MIDL_user_free(void *pb)
{
SCrdEnrollFree(pb);
}
LPVOID SCrdEnrollAlloc (ULONG cbSize)
{
return CoTaskMemAlloc(cbSize);
}
LPVOID SCrdEnrollRealloc (
LPVOID pv,
ULONG cbSize)
{
LPVOID pvTemp=NULL;
if(NULL==pv)
return CoTaskMemAlloc(cbSize);
return CoTaskMemRealloc(pv, cbSize);
}
VOID SCrdEnrollFree (LPVOID pv)
{
if (pv)
CoTaskMemFree(pv);
}
BOOL CertTypeFlagsToGenKeyFlags(IN OPTIONAL DWORD dwEnrollmentFlags,
IN OPTIONAL DWORD dwSubjectNameFlags,
IN OPTIONAL DWORD dwPrivateKeyFlags,
IN OPTIONAL DWORD dwGeneralFlags,
OUT DWORD *pdwGenKeyFlags)
{
// Define a locally scoped helper function. This allows us to gain the benefits of procedural
// abstraction without corrupting the global namespace.
//
LocalScope(CertTypeMap):
// Maps cert type flags of one category (enrollment flags, private key flags, etc...)
// to their corresponding gen key flags. This function always returns successfully.
//
DWORD mapOneCertTypeCategory(IN DWORD dwOption, IN DWORD dwCertTypeFlags)
{
static DWORD const rgdwEnrollmentFlags[][2] = {
{ 0, 0 } // No enrollment flags mapped.
};
static DWORD const rgdwSubjectNameFlags[][2] = {
{ 0, 0 } // No subject name flags mapped.
};
static DWORD const rgdwPrivateKeyFlags[][2] = {
{ CT_FLAG_EXPORTABLE_KEY, CRYPT_EXPORTABLE }
};
static DWORD const rgdwGeneralFlags[][2] = {
{ 0, 0 } // No general flags mapped.
};
static DWORD const dwEnrollmentLen = sizeof(rgdwEnrollmentFlags) / sizeof(DWORD[2]);
static DWORD const dwSubjectNameLen = sizeof(rgdwSubjectNameFlags) / sizeof(DWORD[2]);
static DWORD const dwPrivateKeyLen = sizeof(rgdwPrivateKeyFlags) / sizeof(DWORD[2]);
static DWORD const dwGeneralLen = sizeof(rgdwGeneralFlags) / sizeof(DWORD[2]);
static DWORD const CERT_TYPE_INDEX = 0;
static DWORD const GEN_KEY_INDEX = 1;
DWORD const *pdwFlags;
DWORD dwLen, dwIndex, dwResult = 0;
switch (dwOption)
{
case CERTTYPE_ENROLLMENT_FLAG:
pdwFlags = &rgdwEnrollmentFlags[0][0];
dwLen = dwEnrollmentLen;
break;
case CERTTYPE_SUBJECT_NAME_FLAG:
pdwFlags = &rgdwSubjectNameFlags[0][0];
dwLen = dwSubjectNameLen;
break;
case CERTTYPE_PRIVATE_KEY_FLAG:
pdwFlags = &rgdwPrivateKeyFlags[0][0];
dwLen = dwPrivateKeyLen;
break;
case CERTTYPE_GENERAL_FLAG:
pdwFlags = &rgdwGeneralFlags[0][0];
dwLen = dwGeneralLen;
break;
}
for (dwIndex = 0; dwIndex < dwLen; dwIndex++)
{
if (0 != (pdwFlags[CERT_TYPE_INDEX] & dwCertTypeFlags))
{
dwResult |= pdwFlags[GEN_KEY_INDEX];
}
pdwFlags += 2;
}
return dwResult;
}
EndLocalScope;
//
// Begin procedure body:
//
BOOL fResult;
DWORD dwResult = 0;
DWORD dwErr = ERROR_SUCCESS;
// Input parameter validation:
_JumpConditionWithExpr(pdwGenKeyFlags == NULL, Error, dwErr = ERROR_INVALID_PARAMETER);
// Compute the gen key flags using the locally scope function.
dwResult |= local.mapOneCertTypeCategory(CERTTYPE_ENROLLMENT_FLAG, dwEnrollmentFlags);
dwResult |= local.mapOneCertTypeCategory(CERTTYPE_SUBJECT_NAME_FLAG, dwSubjectNameFlags);
dwResult |= local.mapOneCertTypeCategory(CERTTYPE_PRIVATE_KEY_FLAG, dwPrivateKeyFlags);
dwResult |= local.mapOneCertTypeCategory(CERTTYPE_GENERAL_FLAG, dwGeneralFlags);
// Assign the out parameter:
*pdwGenKeyFlags = dwResult;
fResult = TRUE;
CommonReturn:
return fResult;
Error:
fResult = FALSE;
SetLastError(dwErr);
goto CommonReturn;
}
//----------------------------------------------------------------------------
// CallBack fro cert selection call back
//
//----------------------------------------------------------------------------
BOOL WINAPI SelectSignCertCallBack(
PCCERT_CONTEXT pCertContext,
BOOL *pfInitialSelectedCert,
void *pvCallbackData)
{
BOOL fRet = FALSE;
DWORD cbData=0;
SCrdEnroll_CERT_SELECT_INFO *pCertSelectInfo;
PCERT_ENHKEY_USAGE pUsage = NULL;
CHAR *pszOID = NULL;
DWORD i;
BOOL fFoundOid;
if(!pCertContext)
{
goto done;
}
//the certificate has to have the CERT_KEY_PROV_INFO_PROP_ID
if(!CertGetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&cbData))
{
goto done;
}
if(0==cbData)
{
goto done;
}
pCertSelectInfo = (SCrdEnroll_CERT_SELECT_INFO *)pvCallbackData;
if(NULL == pCertSelectInfo)
{
goto done;
}
if (NULL == pCertSelectInfo->pwszCertTemplateName ||
L'\0' == pCertSelectInfo->pwszCertTemplateName[0])
{
goto done;
}
switch (pCertSelectInfo->dwFlags)
{
case SCARD_SELECT_TEMPLATENAME:
//ask to check template name
if(!VerifyCertTemplateName(
pCertContext,
pCertSelectInfo->pwszCertTemplateName))
{
goto done;
}
break;
case SCARD_SELECT_EKU:
cbData = 0;
while (TRUE)
{
cbData = WideCharToMultiByte(
GetACP(),
0,
pCertSelectInfo->pwszCertTemplateName,
-1,
pszOID,
cbData,
NULL,
NULL);
if(0 == cbData)
{
goto done;
}
if (NULL != pszOID)
{
break;
}
pszOID = (CHAR*)LocalAlloc(LMEM_FIXED, cbData);
if (NULL == pszOID)
{
goto done;
}
}
cbData = 0;
while (TRUE)
{
if (!CertGetEnhancedKeyUsage(
pCertContext,
CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG,
pUsage,
&cbData))
{
goto done;
}
if (NULL != pUsage)
{
//done
break;
}
pUsage = (PCERT_ENHKEY_USAGE)LocalAlloc(LMEM_FIXED, cbData);
if (NULL == pUsage)
{
goto done;
}
}
fFoundOid = FALSE;
for (i = 0 ; i < pUsage->cUsageIdentifier; ++i)
{
if (0 == strcmp(pszOID, pUsage->rgpszUsageIdentifier[i]))
{
fFoundOid = TRUE;
break;
}
}
if (!fFoundOid)
{
//not found
goto done;
}
break;
default:
//invalid_parameter
goto done;
}
//make sure the certificate pass the chain building
if(!VerifyCertChain(pCertContext))
{
goto done;
}
fRet = TRUE;
done:
if (NULL != pUsage)
{
LocalFree(pUsage);
}
if (NULL != pszOID)
{
LocalFree(pszOID);
}
return fRet;
}
//-------------------------------------------------------------------------
// GetName
//
//--------------------------------------------------------------------------
BOOL GetName(LPWSTR pwszName,
EXTENDED_NAME_FORMAT NameFormat,
EXTENDED_NAME_FORMAT DesiredFormat,
LPWSTR *ppwszDesiredName)
{
BOOL fResult = FALSE;
DWORD cbSize = 0;
*ppwszDesiredName = NULL;
if(!TranslateNameW(
pwszName,
NameFormat,
DesiredFormat,
NULL,
&cbSize))
goto TraceErr;
*ppwszDesiredName=(LPWSTR)SCrdEnrollAlloc((cbSize + 1) * sizeof(WCHAR));
if(NULL == *ppwszDesiredName)
goto MemoryErr;
if(!TranslateNameW(
pwszName,
NameFormat,
DesiredFormat,
*ppwszDesiredName,
&cbSize))
goto TraceErr;
fResult = TRUE;
CommonReturn:
return fResult;
ErrorReturn:
if(*ppwszDesiredName)
{
SCrdEnrollFree(*ppwszDesiredName);
*ppwszDesiredName = NULL;
}
fResult = FALSE;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
}
//-------------------------------------------------------------------------
// VerifyCertChain
//
//--------------------------------------------------------------------------
BOOL VerifyCertChain(PCCERT_CONTEXT pCertContext)
{
PCCERT_CHAIN_CONTEXT pCertChainContext = NULL;
CERT_CHAIN_PARA CertChainPara;
BOOL fResult=FALSE;
DWORD dwChainError=CERT_TRUST_IS_NOT_TIME_VALID |
CERT_TRUST_IS_NOT_TIME_NESTED |
CERT_TRUST_IS_REVOKED |
CERT_TRUST_IS_NOT_SIGNATURE_VALID |
CERT_TRUST_IS_NOT_VALID_FOR_USAGE |
CERT_TRUST_IS_UNTRUSTED_ROOT |
CERT_TRUST_IS_CYCLIC |
CERT_TRUST_IS_PARTIAL_CHAIN |
CERT_TRUST_CTL_IS_NOT_TIME_VALID |
CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID |
CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE;
memset(&CertChainPara, 0, sizeof(CertChainPara));
CertChainPara.cbSize = sizeof(CertChainPara);
if (!CertGetCertificateChain(
HCCE_CURRENT_USER,
pCertContext,
NULL,
NULL,
&CertChainPara,
CERT_CHAIN_REVOCATION_CHECK_CHAIN,
NULL,
&pCertChainContext))
goto CLEANUP;
//
// make sure there is at least 1 simple chain
//
if (pCertChainContext->cChain == 0)
goto CLEANUP;
// make sure that we have a good simple chain
if(dwChainError & (pCertChainContext->rgpChain[0]->TrustStatus.dwErrorStatus))
goto CLEANUP;
fResult = TRUE;
CLEANUP:
if (pCertChainContext != NULL)
CertFreeCertificateChain(pCertChainContext);
return fResult;
}
//-------------------------------------------------------------------------
// VerifyCertTemplateName
//
//--------------------------------------------------------------------------
BOOL VerifyCertTemplateName(PCCERT_CONTEXT pCertContext,
LPWSTR pwszCertTemplateName)
{
BOOL fResult=FALSE;
PCERT_EXTENSION pCertTypeExtension=NULL;
DWORD cbCertType=0;
CERT_NAME_VALUE *pCertType=NULL;
if((!pCertContext) || (!pwszCertTemplateName))
goto CLEANUP;
//find the extension for cert type
if(NULL==(pCertTypeExtension=CertFindExtension(
szOID_ENROLL_CERTTYPE_EXTENSION,
pCertContext->pCertInfo->cExtension,
pCertContext->pCertInfo->rgExtension)))
goto CLEANUP;
if(!CryptDecodeObject(pCertContext->dwCertEncodingType,
X509_UNICODE_ANY_STRING,
pCertTypeExtension->Value.pbData,
pCertTypeExtension->Value.cbData,
0,
NULL,
&cbCertType) || (0==cbCertType))
goto CLEANUP;
pCertType=(CERT_NAME_VALUE *)SCrdEnrollAlloc(cbCertType);
if(NULL==pCertType)
goto CLEANUP;
if(!CryptDecodeObject(pCertContext->dwCertEncodingType,
X509_UNICODE_ANY_STRING,
pCertTypeExtension->Value.pbData,
pCertTypeExtension->Value.cbData,
0,
(void *)pCertType,
&cbCertType))
goto CLEANUP;
if(0 != _wcsicmp((LPWSTR)(pCertType->Value.pbData), pwszCertTemplateName))
goto CLEANUP;
fResult=TRUE;
CLEANUP:
if(pCertType)
SCrdEnrollFree(pCertType);
return fResult;
}
//----------------------------------------------------------------------------
//
// CopyWideString
//
//----------------------------------------------------------------------------
LPWSTR CopyWideString(LPCWSTR wsz)
{
DWORD cch = 0;
LPWSTR wszOut = NULL;
if(wsz == NULL) {
SetLastError(ERROR_INVALID_PARAMETER);
return(NULL);
}
cch = wcslen(wsz) + 1;
if( (wszOut = (LPWSTR) SCrdEnrollAlloc(sizeof(WCHAR) * cch)) == NULL ) {
SetLastError(ERROR_OUTOFMEMORY);
return(NULL);
}
wcscpy(wszOut, wsz);
return(wszOut);
}
//----------------------------------------------------------------------------
//
// CopyWideStrings
//
//----------------------------------------------------------------------------
LPWSTR* CopyWideStrings(LPWSTR* rgpwsz)
{
DWORD dwCount = 1;
DWORD dwIndex = 0;
DWORD cb = 0;
LPWSTR *ppwsz;
LPWSTR *rgpwszOut = NULL;
LPWSTR pwszCur;
if (NULL != rgpwsz)
{
//get count of strings
for (ppwsz = rgpwsz; NULL != *ppwsz; ppwsz++)
{
++dwCount;
cb += (wcslen(*ppwsz) + 1) * sizeof(WCHAR);
}
}
// allocate buffer
rgpwszOut = (LPWSTR*)SCrdEnrollAlloc(dwCount * sizeof(WCHAR*) + cb);
if (NULL == rgpwszOut)
{
SetLastError(ERROR_OUTOFMEMORY);
goto error;
}
if (NULL != rgpwsz)
{
pwszCur = (LPWSTR)(rgpwszOut + dwCount);
for(ppwsz = rgpwsz; NULL != *ppwsz; ppwsz++)
{
rgpwszOut[dwIndex] = pwszCur;
wcscpy(pwszCur, *ppwsz);
pwszCur += wcslen(pwszCur) + 1;
++dwIndex;
}
}
rgpwszOut[dwIndex] = NULL;
error:
return(rgpwszOut);
}
//--------------------------------------------------------------------------
//
// Decode a generic BLOB
//
//--------------------------------------------------------------------------
BOOL DecodeGenericBLOB(DWORD dwEncodingType, LPCSTR lpszStructType,
const BYTE *pbEncoded, DWORD cbEncoded,void **ppStructInfo)
{
DWORD cbStructInfo=0;
//decode the object. No copying
if(!CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded, cbEncoded,
0,NULL, &cbStructInfo))
return FALSE;
*ppStructInfo=SCrdEnrollAlloc(cbStructInfo);
if(!(*ppStructInfo))
{
SetLastError(E_OUTOFMEMORY);
return FALSE;
}
return CryptDecodeObject(dwEncodingType,lpszStructType,pbEncoded, cbEncoded,
0,*ppStructInfo,&cbStructInfo);
}
//----------------------------------------------------------------------------
//
// GetNameFromPKCS10
//
//----------------------------------------------------------------------------
BOOL GetNameFromPKCS10(BYTE *pbPKCS10,
DWORD cbPKCS10,
DWORD dwFlags,
LPSTR pszOID,
LPWSTR *ppwszName)
{
BOOL fResult=FALSE;
DWORD errBefore= GetLastError();
DWORD dwRDNIndex=0;
DWORD dwAttrCount=0;
DWORD dwAttrIndex=0;
CERT_RDN_ATTR *pCertRDNAttr=NULL;
CERT_REQUEST_INFO *pCertRequestInfo=NULL;
CERT_NAME_INFO *pCertNameInfo=NULL;
*ppwszName=NULL;
if(!DecodeGenericBLOB(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
X509_CERT_REQUEST_TO_BE_SIGNED,
pbPKCS10,
cbPKCS10,
(void **)&pCertRequestInfo))
goto TraceErr;
if(!DecodeGenericBLOB(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
X509_UNICODE_NAME,
(pCertRequestInfo->Subject).pbData,
(pCertRequestInfo->Subject).cbData,
(void **)&pCertNameInfo))
goto TraceErr;
//search for the OID requested.
*ppwszName = (LPWSTR)SCrdEnrollAlloc(sizeof(WCHAR));
if(NULL == (*ppwszName))
goto MemoryErr;
*(*ppwszName)=L'\0';
for(dwRDNIndex=0; dwRDNIndex<pCertNameInfo->cRDN; dwRDNIndex++)
{
dwAttrCount=(pCertNameInfo->rgRDN)[dwRDNIndex].cRDNAttr;
for(dwAttrIndex=0; dwAttrIndex<dwAttrCount; dwAttrIndex++)
{
pCertRDNAttr=&((pCertNameInfo->rgRDN)[dwRDNIndex].rgRDNAttr[dwAttrIndex]);
if(_stricmp(pszOID, pCertRDNAttr->pszObjId)==0)
{
if(0 != wcslen(*ppwszName))
wcscat(*ppwszName, L"; ");
(*ppwszName) = (LPWSTR)SCrdEnrollRealloc
(*ppwszName, sizeof(WCHAR) *
(wcslen(*ppwszName) + wcslen(L"; ") +
wcslen((LPWSTR)((pCertRDNAttr->Value).pbData))+1));
if(NULL == *ppwszName)
goto MemoryErr;
wcscat(*ppwszName, (LPWSTR)((pCertRDNAttr->Value).pbData));
}
}
}
if(0 == wcslen(*ppwszName))
goto NotFindErr;
fResult=TRUE;
CommonReturn:
if(pCertRequestInfo)
SCrdEnrollFree(pCertRequestInfo);
if(pCertNameInfo)
SCrdEnrollFree(pCertNameInfo);
SetLastError(errBefore);
return fResult;
ErrorReturn:
errBefore = GetLastError();
if(*ppwszName)
{
SCrdEnrollFree(*ppwszName);
*ppwszName=NULL;
}
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
SET_ERROR(NotFindErr, CRYPT_E_NOT_FOUND);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//----------------------------------------------------------------------------
//
// SearchAndDeleteCert
//
//----------------------------------------------------------------------------
BOOL SearchAndDeleteCert(PCCERT_CONTEXT pCertContext)
{
BOOL fResult=FALSE;
DWORD errBefore= GetLastError();
HCERTSTORE hCertStore=NULL;
PCCERT_CONTEXT pFoundCert=NULL;
CERT_BLOB HashBlob;
memset(&HashBlob, 0, sizeof(CERT_BLOB));
if(NULL==pCertContext)
goto InvalidArgErr;
//open the temporary store
hCertStore=CertOpenStore(CERT_STORE_PROV_SYSTEM_W,
g_dwMsgAndCertEncodingType,
NULL,
CERT_SYSTEM_STORE_CURRENT_USER,
g_MyStoreName);
if(NULL==hCertStore)
goto TraceErr;
//get the SHA1 hash
if(!CertGetCertificateContextProperty(
pCertContext,
CERT_SHA1_HASH_PROP_ID,
NULL,
&(HashBlob.cbData)))
goto TraceErr;
HashBlob.pbData=(BYTE *)SCrdEnrollAlloc(HashBlob.cbData);
if(NULL==(HashBlob.pbData))
goto MemoryErr;
if(!CertGetCertificateContextProperty(
pCertContext,
CERT_SHA1_HASH_PROP_ID,
HashBlob.pbData,
&(HashBlob.cbData)))
goto TraceErr;
pFoundCert=CertFindCertificateInStore(
hCertStore,
X509_ASN_ENCODING,
0,
CERT_FIND_SHA1_HASH,
&HashBlob,
NULL);
if(pFoundCert)
CertDeleteCertificateFromStore(pFoundCert);
fResult=TRUE;
CommonReturn:
if(hCertStore)
CertCloseStore(hCertStore, 0);
if(HashBlob.pbData)
SCrdEnrollFree(HashBlob.pbData);
SetLastError(errBefore);
return fResult;
ErrorReturn:
errBefore = GetLastError();
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
}
//--------------------------------------------------------------------------
//
// FormatMessageUnicode
//
//--------------------------------------------------------------------------
BOOL FormatMessageUnicode(LPWSTR *ppwszFormat,LPWSTR wszFormat,...)
{
va_list argList;
DWORD cbMsg=0;
BOOL fResult=FALSE;
HRESULT hr=S_OK;
if(NULL == ppwszFormat)
goto InvalidArgErr;
// format message into requested buffer
va_start(argList, wszFormat);
cbMsg = FormatMessageU(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
wszFormat,
0, // dwMessageId
0, // dwLanguageId
(LPWSTR) (ppwszFormat),
0, // minimum size to allocate
&argList);
va_end(argList);
if(!cbMsg)
goto FormatMessageError;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(FormatMessageError);
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//-----------------------------------------------------------------------
//
// IsNewerCert
//
// Return TRUE is pFirstCert has a later starting date of pSecondCert
//------------------------------------------------------------------------
BOOL IsNewerCert(PCCERT_CONTEXT pFirstCert,
PCCERT_CONTEXT pSecondCert)
{
if(NULL == pSecondCert)
return TRUE;
if(NULL == pFirstCert)
return FALSE;
if(1 != CompareFileTime(&(pFirstCert->pCertInfo->NotBefore),
&(pSecondCert->pCertInfo->NotBefore)))
return FALSE;
return TRUE;
}
//-----------------------------------------------------------------------
//
// SmartCardCSP
//
// Return TRUE is the CSP is a smart card CSP. If anything went wrong,
// we will return TRUE for as a safe guard.
//------------------------------------------------------------------------
BOOL SmartCardCSP(PCCERT_CONTEXT pCertContext)
{
BOOL fResult = TRUE;
DWORD cbData = 0;
DWORD dwImpType=0;
CRYPT_KEY_PROV_INFO *pProvInfo=NULL;
HCRYPTPROV hProv = NULL;
if(NULL == pCertContext)
goto CLEANUP;
//the certificate has to have the CERT_KEY_PROV_INFO_PROP_ID
if(!CertGetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&cbData))
goto CLEANUP;
if((cbData == 0) || (NULL == (pProvInfo =(CRYPT_KEY_PROV_INFO *)SCrdEnrollAlloc(cbData))))
goto CLEANUP;
if(!CertGetCertificateContextProperty(pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
pProvInfo,
&cbData))
goto CLEANUP;
if(!CryptAcquireContextU(&hProv,
NULL,
pProvInfo->pwszProvName,
pProvInfo->dwProvType,
CRYPT_VERIFYCONTEXT))
goto CLEANUP;
cbData = sizeof(dwImpType);
if(!CryptGetProvParam(hProv,
PP_IMPTYPE,
(BYTE *)(&dwImpType),
&cbData,
0))
goto CLEANUP;
if(0 == (CRYPT_IMPL_REMOVABLE & dwImpType))
fResult = FALSE;
CLEANUP:
if(hProv)
CryptReleaseContext(hProv, 0);
if(pProvInfo)
SCrdEnrollFree(pProvInfo);
return fResult;
}
//-----------------------------------------------------------------------
//
// ChKInsertedCardSigningCert
//
// This function checks to see if the inserted smart card matches
// the signing certificate. That is, they are actually the same cert
// with the same public key
//
//------------------------------------------------------------------------
BOOL ChKInsertedCardSigningCert(LPWSTR pwszInsertProvider,
DWORD dwInsertProviderType,
LPWSTR pwszReaderName,
PCCERT_CONTEXT pSignCertContext,
LPSTR pszSignProvider,
DWORD dwSignProviderType,
LPSTR pszSignContainer,
BOOL *pfSame)
{
BOOL fResult=FALSE;
DWORD cbData=0;
CRYPT_KEY_PROV_INFO *pKeyProvInfo=NULL;
CERT_PUBLIC_KEY_INFO *pPubInfo=NULL;
HCRYPTPROV hProv=NULL;
LPWSTR pwszInsertContainer=NULL;
LPWSTR pwszSignProvider=NULL;
if(NULL==pwszInsertProvider || NULL == pwszReaderName ||
NULL == pSignCertContext || NULL == pszSignProvider ||
NULL == pszSignContainer || NULL == pfSame)
goto InvalidArgErr;
*pfSame=FALSE;
//get the key specification from the signing cert
if(!CertGetCertificateContextProperty(
pSignCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
NULL,
&cbData) || (0==cbData))
goto TraceErr;
pKeyProvInfo=(CRYPT_KEY_PROV_INFO *)SCrdEnrollAlloc(cbData);
if(NULL==pKeyProvInfo)
goto MemoryErr;
if(!CertGetCertificateContextProperty(
pSignCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
pKeyProvInfo,
&cbData))
goto TraceErr;
//build a default container name with the reader information
if(!FormatMessageUnicode(&pwszInsertContainer,
L"\\\\.\\%1!s!\\",
pwszReaderName))
goto TraceErr;
//get the hProv from the reader's card
if(!CryptAcquireContextU(&hProv,
pwszInsertContainer,
pwszInsertProvider,
dwInsertProviderType,
CRYPT_SILENT))
{
//check to see if we have an empty card
if((GetLastError() == NTE_BAD_KEYSET) ||
(GetLastError() == NTE_KEYSET_NOT_DEF))
{
//we have an empty card
*pfSame=FALSE;
fResult=TRUE;
goto CommonReturn;
}
else
goto TraceErr;
}
//get the public key information
cbData=0;
if(!CryptExportPublicKeyInfo(hProv,
pKeyProvInfo->dwKeySpec,
pSignCertContext->dwCertEncodingType,
NULL,
&cbData) || (0 == cbData))
{
//the insert card does not have a private key
*pfSame=FALSE;
fResult=TRUE;
goto CommonReturn;
}
pPubInfo = (CERT_PUBLIC_KEY_INFO *)SCrdEnrollAlloc(cbData);
if(NULL == pPubInfo)
goto MemoryErr;
if(!CryptExportPublicKeyInfo(hProv,
pKeyProvInfo->dwKeySpec,
pSignCertContext->dwCertEncodingType,
pPubInfo,
&cbData))
{
//the insert card does not have a private key
*pfSame=FALSE;
fResult=TRUE;
goto CommonReturn;
}
if(CertComparePublicKeyInfo(pSignCertContext->dwCertEncodingType,
pPubInfo,
&(pSignCertContext->pCertInfo->SubjectPublicKeyInfo)))
{
//make sure that we have the same CSP name
pwszSignProvider=MkWStr(pszSignProvider);
if(NULL != pwszSignProvider)
{
//case insensitive compare of the two csp names
if(0 == _wcsicmp(pwszSignProvider, pwszInsertProvider))
*pfSame=TRUE;
else
*pfSame=FALSE;
}
else
{
//we are out of memory. Assume same CSP here
*pfSame=TRUE;
}
}
else
*pfSame=FALSE;
fResult=TRUE;
CommonReturn:
if(pwszSignProvider)
FreeWStr(pwszSignProvider);
if(pPubInfo)
SCrdEnrollFree(pPubInfo);
if(pKeyProvInfo)
SCrdEnrollFree(pKeyProvInfo);
if(hProv)
CryptReleaseContext(hProv, 0);
if(pwszInsertContainer)
LocalFree((HLOCAL)pwszInsertContainer);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//-----------------------------------------------------------------------
//
// DeleteKeySet
//
// If the user's smart card is not empty, we delete the private key
//
//------------------------------------------------------------------------
BOOL DeleteKeySet(LPWSTR pwszUserCSPName,
DWORD dwUserCSPType,
LPWSTR pwszReaderName)
{
BOOL fResult=FALSE;
DWORD dwSize=0;
HCRYPTPROV hDeleteProv=NULL; //no need to free this
HCRYPTPROV hProv=NULL;
LPWSTR pwszDefaultContainer=NULL;
LPSTR pszContainer=NULL;
LPWSTR pwszContainer=NULL;
if(NULL == pwszUserCSPName || NULL == pwszReaderName)
goto InvalidArgErr;
if(!FormatMessageUnicode(&pwszDefaultContainer,
L"\\\\.\\%1!s!\\",
pwszReaderName))
goto TraceErr;
//get the hProv from the reader's card
if(!CryptAcquireContextU(&hProv,
pwszDefaultContainer,
pwszUserCSPName,
dwUserCSPType,
CRYPT_SILENT))
{
//check to see if we have an empty card
if((GetLastError() == NTE_BAD_KEYSET) ||
(GetLastError() == NTE_KEYSET_NOT_DEF))
{
//we have an empty card
fResult=TRUE;
goto CommonReturn;
}
else
goto TraceErr;
}
//get the container name
dwSize = 0;
if(!CryptGetProvParam(hProv,
PP_CONTAINER,
NULL,
&dwSize,
0) || (0==dwSize))
goto TraceErr;
pszContainer = (LPSTR) SCrdEnrollAlloc(dwSize);
if(NULL == pszContainer)
goto MemoryErr;
if(!CryptGetProvParam(hProv,
PP_CONTAINER,
(BYTE *)pszContainer,
&dwSize,
0))
goto TraceErr;
//release the context
if(hProv)
{
CryptReleaseContext(hProv, 0);
hProv=NULL;
}
//build the fully qualified container name
if(!FormatMessageUnicode(&pwszContainer,
L"\\\\.\\%1!s!\\%2!S!",
pwszReaderName,
pszContainer))
goto TraceErr;
//delete the container
if(!CryptAcquireContextU(&hDeleteProv,
pwszContainer,
pwszUserCSPName,
dwUserCSPType,
CRYPT_DELETEKEYSET))
{
//check to see if we have an empty card
if(GetLastError() == NTE_BAD_KEYSET)
{
//we have an empty card
fResult=TRUE;
goto CommonReturn;
}
else
goto TraceErr;
}
fResult=TRUE;
CommonReturn:
if(pwszDefaultContainer)
LocalFree((HLOCAL)pwszDefaultContainer);
if(pwszContainer)
LocalFree((HLOCAL)pwszContainer);
if(pszContainer)
SCrdEnrollFree(pszContainer);
if(hProv)
CryptReleaseContext(hProv, 0);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//-----------------------------------------------------------------------
//
// ChkSCardStatus
//
// This function makes sure that the smart card enrollment station has the
// correct number of readers connected to the station, and the correct number
// of smart cards inserted into the readers. If everything looks good,
// the user smart card is initialized (old key container deleted) and a fully
// qualified key container name, in the format of "\\.\ReaderName\ContainerName",
// will be returned.
//
//------------------------------------------------------------------------
HRESULT ChkSCardStatus(BOOL fSCardSigningCert,
PCCERT_CONTEXT pSigningCertCertContext,
LPSTR pszCSPNameSigningCert,
DWORD dwCSPTypeSigningCert,
LPSTR pszContainerSigningCert,
LPWSTR pwszSelectedCSP,
LPWSTR *ppwszNewContainerName)
{
HRESULT hr=E_FAIL;
DWORD dwExpectedReader=0;
DWORD dwReader=0;
DWORD dwSCard=0;
WCHAR wszProvider[MAX_PATH];
DWORD dwProviderType=0;
DWORD dwCount=0;
BOOL fFindSigningCert=FALSE;
DWORD errBefore=0;
BOOL fSameCert=FALSE;
DWORD dwUserCSPType=0;
LPCWSTR pwszReaderName=NULL; //no need to free. Point to internal data
LPWSTR pwszUserReaderName=NULL; //no need to free . Point to internal data
GUID guidContainerName;
LPVOID pvContext = NULL;
LPWSTR pwszNewContainerName=NULL;
LPWSTR pwszUserCSPName=NULL;
char * sz = NULL;
RPC_STATUS rpc_status;
if(NULL == pszCSPNameSigningCert || NULL == pszContainerSigningCert ||
NULL == ppwszNewContainerName || NULL == pSigningCertCertContext ||
NULL == pwszSelectedCSP)
goto CLEANUP;
*ppwszNewContainerName=NULL;
if(fSCardSigningCert)
dwExpectedReader=2;
else
dwExpectedReader=1;
dwReader = CountReaders(NULL);
//check the # of smart card readers
if(dwReader < dwExpectedReader)
{
hr=SCARD_E_READER_UNAVAILABLE;
goto CLEANUP;
}
dwSCard = ScanReaders(&pvContext);
//no smart card is inserted
if( 0 == dwSCard || NULL == pvContext)
{
hr=SCARD_E_NO_SMARTCARD;
goto CLEANUP;
}
//we have more than expected # of smart card inserted
if(dwSCard > dwExpectedReader)
{
// seems ERROR_TOO_MANY_OPEN_FILES is closest one for this case
hr=HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES);
goto CLEANUP;
}
dwCount=0;
dwProviderType=0;
wszProvider[0]=L'\0';
pwszReaderName=NULL;
fSameCert=FALSE;
//now, we loop through we all inserted cards and make sure:
//1. We find the signing certificate if applicable
//2. We find a valid user certificate
while (EnumInsertedCards(
pvContext,
wszProvider,
sizeof(wszProvider)/sizeof(wszProvider[0]),
&dwProviderType,
&pwszReaderName))
{
if((NULL == pwszReaderName) || (0 == wcslen(wszProvider)))
{
//we can not determine the status of the smart card
hr = SCARD_E_CARD_UNSUPPORTED;
goto CLEANUP;
}
if (!ChKInsertedCardSigningCert(
wszProvider,
dwProviderType,
(LPWSTR)pwszReaderName,
pSigningCertCertContext,
pszCSPNameSigningCert,
dwCSPTypeSigningCert,
pszContainerSigningCert,
&fSameCert))
{
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
hr = CodeToHR(GetLastError());
goto CLEANUP;
}
if(TRUE == fSameCert)
{
if(TRUE == fSCardSigningCert)
{
if(TRUE == fFindSigningCert)
{
//too many signing cards. Not expected
hr = SCARD_E_CARD_UNSUPPORTED;
goto CLEANUP;
}
else
fFindSigningCert=TRUE;
}
else
{
//we should not expect a siging certificate
hr=SCARD_E_CARD_UNSUPPORTED;
goto CLEANUP;
}
}
else
{
//this is a user card.
if(NULL != (pwszUserCSPName))
{
//too many user cards.
// seems ERROR_TOO_MANY_OPEN_FILES is closest one for this case
hr=HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES);
goto CLEANUP;
}
pwszUserCSPName = CopyWideString(wszProvider);
if(NULL == pwszUserCSPName)
{
hr=E_OUTOFMEMORY;
goto CLEANUP;
}
dwUserCSPType = dwProviderType;
pwszUserReaderName = (LPWSTR)pwszReaderName;
}
dwCount++;
if(dwCount >= dwSCard)
break;
dwProviderType=0;
pwszReaderName=NULL;
wszProvider[0]=L'\0';
fSameCert=FALSE;
}
if((TRUE == fSCardSigningCert) && (FALSE == fFindSigningCert))
{
//we failed to find the signing certificate
hr=SCARD_E_NO_SUCH_CERTIFICATE;
goto CLEANUP;
}
if(NULL == pwszUserCSPName)
{
//we failed to find the target user certificate
hr=SCARD_E_NO_SMARTCARD;
goto CLEANUP;
}
//make sure the pwszUserCSPName matches with the CSP selected by the admin
if(0 != _wcsicmp(pwszUserCSPName, pwszSelectedCSP))
{
hr=SCARD_E_PROTO_MISMATCH;
goto CLEANUP;
}
//delete the key set from the user's certificate
if(!DeleteKeySet(pwszUserCSPName,
dwUserCSPType,
pwszUserReaderName))
{
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
hr = CodeToHR(GetLastError());
goto CLEANUP;
}
//Build the fully qualified container name with a GUID
// get a container based on a guid
rpc_status = UuidCreate(&guidContainerName);
if (RPC_S_OK != rpc_status && RPC_S_UUID_LOCAL_ONLY != rpc_status)
{
hr = rpc_status;
goto CLEANUP;
}
rpc_status = UuidToStringA(&guidContainerName, (unsigned char **) &sz);
if (RPC_S_OK != rpc_status)
{
hr = rpc_status;
goto CLEANUP;
}
if(NULL == sz)
{
hr=E_OUTOFMEMORY;
goto CLEANUP;
}
//although the chance is VERY low, we could generate a same GUID
//as the signing cert's container.
if(0 == _stricmp(sz,pszContainerSigningCert))
{
//we will have to do this again
RpcStringFree((unsigned char **) &sz);
sz=NULL;
rpc_status = UuidCreate(&guidContainerName);
if (RPC_S_OK != rpc_status && RPC_S_UUID_LOCAL_ONLY != rpc_status)
{
hr = rpc_status;
goto CLEANUP;
}
rpc_status = UuidToStringA(&guidContainerName, (unsigned char **) &sz);
if (RPC_S_OK != rpc_status)
{
hr = rpc_status;
goto CLEANUP;
}
if(NULL == sz)
{
hr=E_OUTOFMEMORY;
goto CLEANUP;
}
//since we are guaranted a new GUID, we should be fine here
if(0 == _stricmp(sz,pszContainerSigningCert))
{
//can not support this smart card
hr = SCARD_E_CARD_UNSUPPORTED;
goto CLEANUP;
}
}
if(!FormatMessageUnicode(&pwszNewContainerName,
L"\\\\.\\%1!s!\\%2!S!",
pwszUserReaderName,
sz))
{
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
hr = CodeToHR(GetLastError());
goto CLEANUP;
}
*ppwszNewContainerName = pwszNewContainerName;
pwszNewContainerName = NULL;
hr=S_OK;
CLEANUP:
if(pwszUserCSPName)
SCrdEnrollFree(pwszUserCSPName);
if(sz)
RpcStringFree((unsigned char **) &sz);
if(pvContext)
EndReaderScan(&pvContext);
if(pwszNewContainerName)
LocalFree((HLOCAL)pwszNewContainerName);
return hr;
}
//-----------------------------------------------------------------------
//
// SignWithCert
//
// We sign a dummy message with the signing certificate so that
// the smart card insert cert dialogue will be prompted
//
//------------------------------------------------------------------------
BOOL SignWithCert(LPSTR pszCSPName,
DWORD dwCSPType,
PCCERT_CONTEXT pSigningCert)
{
BOOL fResult=FALSE;
DWORD errBefore= GetLastError();
HRESULT hr=E_FAIL;
CRYPT_SIGN_MESSAGE_PARA signMsgPara;
DWORD cbData=0;
BYTE *pbData=NULL;
IEnroll *pIEnroll=NULL;
LPWSTR pwszCSPName=NULL;
LPWSTR pwszOID=NULL;
LPSTR pszOID=NULL;
char szMessage[] = "MyMessage";
LPSTR pszMessage = szMessage;
BYTE* pbMessage = (BYTE*) pszMessage;
DWORD cbMessage = sizeof(szMessage);
memset(&signMsgPara, 0, sizeof(CRYPT_SIGN_MESSAGE_PARA));
if(NULL == pszCSPName)
goto InvalidArgErr;
pwszCSPName = MkWStr(pszCSPName);
if(NULL == pwszCSPName)
goto MemoryErr;
//use xEnroll to get the correct hash algorithm for the
//CSP
if(NULL == (pIEnroll=PIEnrollGetNoCOM()))
goto TraceErr;
//set the CSP information
if(S_OK != (hr=pIEnroll->put_ProviderType(dwCSPType)))
goto SetErr;
if(S_OK !=(hr=pIEnroll->put_ProviderNameWStr(pwszCSPName)))
goto SetErr;
if(S_OK != (hr=pIEnroll->get_HashAlgorithmWStr(&pwszOID)))
goto SetErr;
if(!MkMBStr(NULL, 0, pwszOID, &pszOID))
goto TraceErr;
signMsgPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
signMsgPara.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;
signMsgPara.pSigningCert = pSigningCert;
signMsgPara.HashAlgorithm.pszObjId = pszOID;
signMsgPara.cMsgCert = 1;
signMsgPara.rgpMsgCert = &pSigningCert;
cbData = 0;
if( !CryptSignMessage(
&signMsgPara,
FALSE,
1,
(const BYTE **) &(pbMessage),
&(cbMessage) ,
NULL,
&cbData)|| (0 == cbData))
goto TraceErr;
pbData = (BYTE *)SCrdEnrollAlloc(cbData);
if(NULL == pbData)
goto MemoryErr;
if( !CryptSignMessage(
&signMsgPara,
FALSE,
1,
(const BYTE **) &(pbMessage),
&(cbMessage) ,
pbData,
&cbData))
goto TraceErr;
fResult=TRUE;
CommonReturn:
if(pbData)
SCrdEnrollFree(pbData);
if(pwszCSPName)
FreeWStr(pwszCSPName);
if(pszOID)
FreeMBStr(NULL,pszOID);
//the memory from xEnroll is freed via LocalFree
//since we use the PIEnrollGetNoCOM function
if(pwszOID)
LocalFree(pwszOID);
if(pIEnroll)
pIEnroll->Release();
SetLastError(errBefore);
return fResult;
ErrorReturn:
errBefore = GetLastError();
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR_VAR(SetErr, hr);
}
//-----------------------------------------------------------------------
//
// GetSelectedUserName
//
//------------------------------------------------------------------------
HRESULT GetSelectedUserName(IDsObjectPicker *pDsObjectPicker,
LPWSTR *ppwszSelectedUserSAM,
LPWSTR *ppwszSelectedUserUPN)
{
HRESULT hr= E_FAIL;
DWORD errBefore= GetLastError();
BOOL fGotStgMedium = FALSE;
LPWSTR pwszPath=NULL;
DWORD dwIndex =0 ;
DWORD dwCount=0;
IDataObject *pdo = NULL;
PDS_SELECTION_LIST pDsSelList=NULL;
WCHAR wszWinNT[]=L"WinNT://";
STGMEDIUM stgmedium =
{
TYMED_HGLOBAL,
NULL,
NULL
};
FORMATETC formatetc =
{
(CLIPFORMAT)g_cfDsObjectPicker,
NULL,
DVASPECT_CONTENT,
-1,
TYMED_HGLOBAL
};
//input check
if((NULL == ppwszSelectedUserSAM) || (NULL == ppwszSelectedUserUPN))
goto InvalidArgErr;
*ppwszSelectedUserSAM = NULL;
*ppwszSelectedUserUPN = NULL;
if(NULL == pDsObjectPicker)
goto InvalidArgErr;
if(S_OK != (hr = pDsObjectPicker->InvokeDialog(NULL, &pdo)))
goto SetErr;
if(S_OK != (hr = pdo->GetData(&formatetc, &stgmedium)))
goto SetErr;
fGotStgMedium = TRUE;
pDsSelList = (PDS_SELECTION_LIST)GlobalLock(stgmedium.hGlobal);
if(!pDsSelList)
goto TraceErr;
//Get the SAM name
if((pDsSelList->aDsSelection[0]).pwzADsPath == NULL)
goto UnexpectedErr;
//the ADsPath is in the form of "WinNT://"
if(wcslen((pDsSelList->aDsSelection[0]).pwzADsPath) <= wcslen(wszWinNT))
goto UnexpectedErr;
if( 0 != _wcsnicmp((pDsSelList->aDsSelection[0]).pwzADsPath, wszWinNT, wcslen(wszWinNT)))
goto UnexpectedErr;
pwszPath = ((pDsSelList->aDsSelection[0]).pwzADsPath) + wcslen(wszWinNT);
*ppwszSelectedUserSAM=CopyWideString(pwszPath);
if(NULL == (*ppwszSelectedUserSAM))
goto MemoryErr;
//search for the "/" and make it "\". Since the ADsPath is in the form
//of "WinNT://domain/name". We need the SAM name in the form of
//domain\name
dwCount = wcslen(*ppwszSelectedUserSAM);
for(dwIndex = 0; dwIndex < dwCount; dwIndex++)
{
if((*ppwszSelectedUserSAM)[dwIndex] == L'/')
{
(*ppwszSelectedUserSAM)[dwIndex] = L'\\';
break;
}
}
//get the UPN name
if((pDsSelList->aDsSelection[0]).pwzUPN != NULL)
{
if(0 != _wcsicmp(L"",(pDsSelList->aDsSelection[0]).pwzUPN))
{
*ppwszSelectedUserUPN= CopyWideString((pDsSelList->aDsSelection[0]).pwzUPN);
if(NULL == (*ppwszSelectedUserUPN))
goto MemoryErr;
//if we already have a UPN name, get the SAM name from TraslateName
if(*ppwszSelectedUserSAM)
{
SCrdEnrollFree(*ppwszSelectedUserSAM);
*ppwszSelectedUserSAM=NULL;
}
if(!GetName(*ppwszSelectedUserUPN,
NameUserPrincipal,
NameSamCompatible,
ppwszSelectedUserSAM))
goto TraceErr;
}
}
hr=S_OK;
CommonReturn:
if(pDsSelList)
GlobalUnlock(stgmedium.hGlobal);
if (TRUE == fGotStgMedium)
ReleaseStgMedium(&stgmedium);
if(pdo)
pdo->Release();
SetLastError(errBefore);
return hr;
ErrorReturn:
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
hr = CodeToHR(errBefore);
//we should free the memory for the output
if(ppwszSelectedUserSAM)
{
if(*ppwszSelectedUserSAM)
{
SCrdEnrollFree(*ppwszSelectedUserSAM);
*ppwszSelectedUserSAM=NULL;
}
}
if(ppwszSelectedUserUPN)
{
if(*ppwszSelectedUserUPN)
{
SCrdEnrollFree(*ppwszSelectedUserUPN);
*ppwszSelectedUserUPN=NULL;
}
}
goto CommonReturn;
SET_ERROR_VAR(SetErr, hr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
SET_ERROR(UnexpectedErr, E_UNEXPECTED);
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//-----------------------------------------------------------------------
//
// CodeToHR
//
//------------------------------------------------------------------------
HRESULT CodeToHR(HRESULT hr)
{
if (S_OK != hr && S_FALSE != hr &&
(!FAILED(hr) || 0x0 == (LONG)HRESULT_FACILITY(hr)))
{
hr = HRESULT_FROM_WIN32(hr);
if (0x0 == (LONG)HRESULT_CODE(hr))
{
// A call failed without properly setting an error condition!
hr = E_UNEXPECTED;
}
}
return(hr);
}
//-----------------------------------------------------------------------
//
// ValidCSP
//
//------------------------------------------------------------------------
BOOL ValidCSP(DWORD dwProviderType, LPWSTR pwszName)
{
HCRYPTPROV hProv=NULL;
BOOL fValid=FALSE;
DWORD dwImpType=0;
DWORD dwSize=sizeof(dwImpType);
if(CryptAcquireContextU(&hProv,
NULL,
pwszName,
dwProviderType,
CRYPT_VERIFYCONTEXT))
{
if(CryptGetProvParam(hProv,
PP_IMPTYPE,
(BYTE *)(&dwImpType),
&dwSize,
0))
{
if(CRYPT_IMPL_REMOVABLE & dwImpType)
fValid=TRUE;
}
}
if(hProv)
CryptReleaseContext(hProv, 0);
return fValid;
}
//-----------------------------------------------------------------------
//
// InitlializeCSPList
//
//------------------------------------------------------------------------
BOOL InitlializeCSPList(DWORD *pdwCSPCount, SCrdEnroll_CSP_INFO **prgCSPInfo)
{
BOOL fResult=FALSE;
DWORD errBefore= GetLastError();
DWORD dwIndex=0;
DWORD dwProviderType=0;
DWORD cbSize=0;
SCrdEnroll_CSP_INFO *rgCSPInfo=NULL;
LPWSTR pwszName=NULL;
*pdwCSPCount=0;
*prgCSPInfo=NULL;
while(CryptEnumProvidersU(
dwIndex,
0,
0,
&dwProviderType,
NULL,
&cbSize))
{
pwszName=(LPWSTR)SCrdEnrollAlloc(cbSize);
if(NULL==pwszName)
goto MemoryErr;
if(!CryptEnumProvidersU(
dwIndex,
0,
0,
&dwProviderType,
pwszName,
&cbSize))
goto TraceErr;
if(ValidCSP(dwProviderType, pwszName))
{
rgCSPInfo=(SCrdEnroll_CSP_INFO *)SCrdEnrollRealloc(*prgCSPInfo,
((*pdwCSPCount) + 1) * sizeof(SCrdEnroll_CSP_INFO));
if(NULL==rgCSPInfo)
goto MemoryErr;
*prgCSPInfo=rgCSPInfo;
memset(&(*prgCSPInfo)[*pdwCSPCount], 0, sizeof(SCrdEnroll_CSP_INFO));
(*prgCSPInfo)[*pdwCSPCount].pwszCSPName=pwszName;
pwszName=NULL;
(*prgCSPInfo)[*pdwCSPCount].dwCSPType=dwProviderType;
(*pdwCSPCount)++;
}
else
{
SCrdEnrollFree(pwszName);
pwszName=NULL;
}
dwIndex++;
dwProviderType=0;
cbSize=0;
}
if((*pdwCSPCount == 0) || (*prgCSPInfo == NULL))
goto NoItemErr;
fResult=TRUE;
CommonReturn:
if(pwszName)
SCrdEnrollFree(pwszName);
SetLastError(errBefore);
return fResult;
ErrorReturn:
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
//we need to free all the memory
FreeCSPInfo(*pdwCSPCount, *prgCSPInfo);
*pdwCSPCount=0;
*prgCSPInfo=NULL;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
TRACE_ERROR(TraceErr);
SET_ERROR(NoItemErr,ERROR_NO_MORE_ITEMS);
}
//-----------------------------------------------------------------------
//
// FreeCSPInfo
//
//------------------------------------------------------------------------
void FreeCSPInfo(DWORD dwCSPCount, SCrdEnroll_CSP_INFO *prgCSPInfo)
{
DWORD dwIndex=0;
if(prgCSPInfo)
{
for(dwIndex=0; dwIndex < dwCSPCount; dwIndex++)
{
if(prgCSPInfo[dwIndex].pwszCSPName)
SCrdEnrollFree(prgCSPInfo[dwIndex].pwszCSPName);
}
SCrdEnrollFree(prgCSPInfo);
}
}
//-----------------------------------------------------------------------
//
// FreeCAInfoElement
//
//------------------------------------------------------------------------
void FreeCAInfoElement(SCrdEnroll_CA_INFO *pCAInfo)
{
if(pCAInfo)
{
if(pCAInfo->pwszCAName)
SCrdEnrollFree(pCAInfo->pwszCAName);
if(pCAInfo->pwszCALocation)
SCrdEnrollFree(pCAInfo->pwszCALocation);
if(pCAInfo->pwszCADisplayName)
SCrdEnrollFree(pCAInfo->pwszCADisplayName);
memset(pCAInfo, 0, sizeof(SCrdEnroll_CA_INFO));
}
}
//-----------------------------------------------------------------------
//
// FreeCAInfo
//
//------------------------------------------------------------------------
void FreeCAInfo(DWORD dwCACount, SCrdEnroll_CA_INFO *rgCAInfo)
{
DWORD dwIndex=0;
if(rgCAInfo)
{
for(dwIndex=0; dwIndex < dwCACount; dwIndex++)
FreeCAInfoElement(&(rgCAInfo[dwIndex]));
SCrdEnrollFree(rgCAInfo);
}
}
//-----------------------------------------------------------------------
//
// FreeCTInfoElement
//
//------------------------------------------------------------------------
void FreeCTInfoElement(SCrdEnroll_CT_INFO * pCTInfo)
{
if(pCTInfo)
{
if(pCTInfo->pCertTypeExtensions)
CAFreeCertTypeExtensions(NULL,pCTInfo->pCertTypeExtensions);
if(pCTInfo->pwszCTName)
SCrdEnrollFree(pCTInfo->pwszCTName);
if(pCTInfo->pwszCTDisplayName)
SCrdEnrollFree(pCTInfo->pwszCTDisplayName);
if(pCTInfo->rgCAInfo)
FreeCAInfo(pCTInfo->dwCACount, pCTInfo->rgCAInfo);
if (NULL != pCTInfo->rgpwszSupportedCSPs)
{
SCrdEnrollFree(pCTInfo->rgpwszSupportedCSPs);
}
memset(pCTInfo, 0, sizeof(SCrdEnroll_CT_INFO));
}
}
//-----------------------------------------------------------------------
//
// FreeCTInfo(DWORD dwCTCount, SCrdEnroll_CT_INFO *rgCTInfo);
//
//------------------------------------------------------------------------
void FreeCTInfo(DWORD dwCTCount, SCrdEnroll_CT_INFO *rgCTInfo)
{
DWORD dwIndex=0;
if(rgCTInfo)
{
for(dwIndex=0; dwIndex < dwCTCount; dwIndex++)
FreeCTInfoElement(&(rgCTInfo[dwIndex]));
SCrdEnrollFree(rgCTInfo);
}
}
//-----------------------------------------------------------------------
//
// GetCertTypeProperties
//
//------------------------------------------------------------------------
BOOL GetCertTypeProperties(HCERTTYPE hCurCertType,
SCrdEnroll_CT_INFO *pCertInfo)
{
BOOL fResult=FALSE;
DWORD errBefore= GetLastError();
HRESULT hr=S_OK;
DWORD dwCertType=0;
DWORD dwMinKeySize;
DWORD dwEnrollmentFlags;
DWORD dwSubjectNameFlags;
DWORD dwPrivateKeyFlags;
DWORD dwGeneralFlags;
DWORD dwGenKeyFlags;
LPWSTR *rgpwszSupportedCSPs = NULL;
LPWSTR *ppwszDisplayCertTypeName=NULL;
LPWSTR *ppwszCertTypeName=NULL;
if((NULL==pCertInfo) || (NULL == hCurCertType))
goto InvalidArgErr;
//
// Get all of the cert type flags.
//
// Get enrollment flags:
if (S_OK != (hr=MyCAGetCertTypeFlagsEx
(hCurCertType,
CERTTYPE_ENROLLMENT_FLAG,
&pCertInfo->dwEnrollmentFlags)))
goto CertCliErr;
// Get subject name flags:
if (S_OK != (hr=MyCAGetCertTypeFlagsEx
(hCurCertType,
CERTTYPE_SUBJECT_NAME_FLAG,
&pCertInfo->dwSubjectNameFlags)))
goto CertCliErr;
// Get private key flags.
if(S_OK != (hr = MyCAGetCertTypeFlagsEx
(hCurCertType,
CERTTYPE_PRIVATE_KEY_FLAG,
&pCertInfo->dwPrivateKeyFlags)))
goto CertCliErr;
// Get general flags:
if (S_OK != (hr=MyCAGetCertTypeFlagsEx
(hCurCertType,
CERTTYPE_GENERAL_FLAG,
&pCertInfo->dwGeneralFlags)))
goto CertCliErr;
//detremine machine boolean flag
pCertInfo->fMachine = (0x0 != (pCertInfo->dwGeneralFlags & CT_FLAG_MACHINE_TYPE)) ? TRUE : FALSE;
// Extract gen key flags from the type flags.
dwGenKeyFlags = 0;
if (!(CertTypeFlagsToGenKeyFlags
(pCertInfo->dwEnrollmentFlags,
pCertInfo->dwSubjectNameFlags,
pCertInfo->dwPrivateKeyFlags,
pCertInfo->dwGeneralFlags,
&pCertInfo->dwGenKeyFlags)))
goto CertCliErr;
// Get key spec:
if(S_OK != (hr= CAGetCertTypeKeySpec(hCurCertType, &(pCertInfo->dwKeySpec))))
goto CertCliErr;
//get the display name of the cert type
hr=CAGetCertTypeProperty(
hCurCertType,
CERTTYPE_PROP_FRIENDLY_NAME,
&ppwszDisplayCertTypeName);
if(S_OK != hr || NULL==ppwszDisplayCertTypeName)
{
if(S_OK == hr)
hr=E_FAIL;
goto CertCliErr;
}
//copy the name
pCertInfo->pwszCTDisplayName=CopyWideString(ppwszDisplayCertTypeName[0]);
if(NULL==(pCertInfo->pwszCTDisplayName))
goto MemoryErr;
//get the machine readable name of the cert type
hr=CAGetCertTypeProperty(
hCurCertType,
CERTTYPE_PROP_DN,
&ppwszCertTypeName);
if(S_OK != hr || NULL==ppwszCertTypeName)
{
if(S_OK == hr)
hr=E_FAIL;
goto CertCliErr;
}
//copy the name
pCertInfo->pwszCTName=CopyWideString(ppwszCertTypeName[0]);
if(NULL==(pCertInfo->pwszCTName))
goto MemoryErr;
//copy the certType extensions
if(S_OK != (hr=CAGetCertTypeExtensions(
hCurCertType,
&(pCertInfo->pCertTypeExtensions))))
goto CertCliErr;
//copy csp list supported by template
hr = CAGetCertTypeProperty(
hCurCertType,
CERTTYPE_PROP_CSP_LIST,
&rgpwszSupportedCSPs);
if (S_OK != hr)
{
goto CertCliErr;
}
pCertInfo->rgpwszSupportedCSPs = CopyWideStrings(rgpwszSupportedCSPs);
if (NULL == pCertInfo->rgpwszSupportedCSPs)
{
goto MemoryErr;
}
pCertInfo->dwCurrentCSP = 0; //first one
//
// Set V2 properties.
// If we're dealing with a v2 cert type, add v2 properties.
// Otherwise, insert defaults.
//
if (S_OK != (hr=MyCAGetCertTypePropertyEx
(hCurCertType,
CERTTYPE_PROP_SCHEMA_VERSION,
&dwCertType)))
goto CertCliErr;
if (dwCertType == CERTTYPE_SCHEMA_VERSION_1)
{
// Just a v1 cert type, it won't have v2 properties.
// Set left half-word of the type flags to 0. This means that
// that the min key size is not specified.
pCertInfo->dwGenKeyFlags &= 0x0000FFFF;
pCertInfo->dwRASignature = 0;
}
else // We must have a v2 (or greater) cert type.
{
// Get the minimum key size of the cert type
if (S_OK != (hr=MyCAGetCertTypePropertyEx
(hCurCertType,
CERTTYPE_PROP_MIN_KEY_SIZE,
(LPVOID)&dwMinKeySize)))
goto CertCliErr;
// store the minimum key size in the left half-word of the
// type flags.
pCertInfo->dwGenKeyFlags =
(dwMinKeySize << 16) | (pCertInfo->dwGenKeyFlags & 0x0000FFFF) ;
// Get the number of RA signatures required for this cert type.
if (S_OK != (hr=MyCAGetCertTypePropertyEx
(hCurCertType,
CERTTYPE_PROP_RA_SIGNATURE,
(LPVOID)(&pCertInfo->dwRASignature))))
goto CertCliErr;
}
fResult=TRUE;
CommonReturn:
if(ppwszDisplayCertTypeName)
CAFreeCertTypeProperty(hCurCertType, ppwszDisplayCertTypeName);
if(ppwszCertTypeName)
CAFreeCertTypeProperty(hCurCertType, ppwszCertTypeName);
if (NULL != rgpwszSupportedCSPs)
{
CAFreeCertTypeProperty(hCurCertType, rgpwszSupportedCSPs);
}
SetLastError(errBefore);
return fResult;
ErrorReturn:
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
//in error case, free the memory and memset to 0
if(pCertInfo)
FreeCTInfoElement(pCertInfo);
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR_VAR(CertCliErr, hr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}
//--------------------------------------------------------------------
//
// IsMachineCertType
//
//--------------------------------------------------------------------
BOOL IsMachineCertType(HCERTTYPE hCertType)
{
DWORD dwCertType=0;
if(S_OK != CAGetCertTypeFlags(hCertType, &dwCertType))
return FALSE;
if(CT_FLAG_MACHINE_TYPE & dwCertType)
return TRUE;
return FALSE;
}
//-----------------------------------------------------------------------
// Get a list of allowed cert types
//
//------------------------------------------------------------------------
/*BOOL GetAllowedCertTypeName(LPWSTR **pawszAllowedCertTypes)
{
DWORD dwErr=0;
KEYSVC_TYPE dwServiceType=KeySvcMachine;
DWORD cTypes=0;
DWORD dwSize=0;
CHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1]={0};
DWORD cbArray = 0;
DWORD i=0;
LPWSTR wszCurrentType;
BOOL fResult=FALSE;
KEYSVCC_HANDLE hKeyService=NULL;
PKEYSVC_UNICODE_STRING pCertTypes = NULL;
dwSize=sizeof(szComputerName);
if(0==GetComputerNameA(szComputerName, &dwSize))
goto TraceErr;
dwErr = KeyOpenKeyService(szComputerName,
dwServiceType,
NULL,
NULL, // no authentication string right now
NULL,
&hKeyService);
if(dwErr != ERROR_SUCCESS)
{
SetLastError(dwErr);
goto TraceErr;
}
dwErr = KeyEnumerateAvailableCertTypes(hKeyService,
NULL,
&cTypes,
&pCertTypes);
if(dwErr != ERROR_SUCCESS)
{
SetLastError(dwErr);
goto TraceErr;
}
cbArray = (cTypes+1)*sizeof(LPWSTR);
// Convert into a simple array
for(i=0; i < cTypes; i++)
{
cbArray += pCertTypes[i].Length;
}
*pawszAllowedCertTypes = (LPWSTR *)SCrdEnrollAlloc(cbArray);
if(*pawszAllowedCertTypes == NULL)
goto MemoryErr;
memset(*pawszAllowedCertTypes, 0, cbArray);
wszCurrentType = (LPWSTR)(&((*pawszAllowedCertTypes)[cTypes + 1]));
for(i=0; i < cTypes; i++)
{
(*pawszAllowedCertTypes)[i] = wszCurrentType;
wcscpy(wszCurrentType, pCertTypes[i].Buffer);
wszCurrentType += wcslen(wszCurrentType)+1;
}
fResult=TRUE;
CommonReturn:
//memory from the KeyService
if(pCertTypes)
LocalFree((HLOCAL)pCertTypes);
if(hKeyService)
KeyCloseKeyService(hKeyService, NULL);
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
TRACE_ERROR(TraceErr);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
} */
//--------------------------------------------------------------------
//
// CheckAccessPermission
//
//--------------------------------------------------------------------
BOOL CheckAccessPermission(HCERTTYPE hCertType)
{
//make sure the principal making this call has access to request
//this cert type, even if he's requesting on behalf of another.
//
HRESULT hr = S_OK;
HANDLE hHandle = NULL;
HANDLE hClientToken = NULL;
hHandle = GetCurrentThread();
if (NULL == hHandle)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
if (!OpenThreadToken(hHandle,
TOKEN_QUERY,
TRUE, // open as self
&hClientToken))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hHandle);
hHandle = NULL;
}
}
if(hr != S_OK)
{
hHandle = GetCurrentProcess();
if (NULL == hHandle)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
HANDLE hProcessToken = NULL;
hr = S_OK;
if (!OpenProcessToken(hHandle,
TOKEN_DUPLICATE,
&hProcessToken))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hHandle);
hHandle = NULL;
}
else
{
if(!DuplicateToken(hProcessToken,
SecurityImpersonation,
&hClientToken))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hHandle);
hHandle = NULL;
}
CloseHandle(hProcessToken);
}
}
}
if(hr == S_OK)
{
hr = CACertTypeAccessCheck(
hCertType,
hClientToken);
CloseHandle(hClientToken);
}
if(hHandle)
{
CloseHandle(hHandle);
}
return (S_OK == hr);
}
//--------------------------------------------------------------------
//
// TokenCheckAccessPermission
//
//--------------------------------------------------------------------
BOOL TokenCheckAccessPermission(HANDLE hToken, HCERTTYPE hCertType)
{
HRESULT hr=E_FAIL;
if(hToken)
{
hr = CACertTypeAccessCheck(
hCertType,
hToken);
return (S_OK == hr);
}
return CheckAccessPermission(hCertType);
}
//--------------------------------------------------------------------
//
// CheckCAPermission
//
//--------------------------------------------------------------------
BOOL CheckCAPermission(HCAINFO hCAInfo)
{
//make sure the principal making this call has access to request
//this cert type, even if he's requesting on behalf of another.
//
HRESULT hr = S_OK;
HANDLE hHandle = NULL;
HANDLE hClientToken = NULL;
hHandle = GetCurrentThread();
if (NULL == hHandle)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
if (!OpenThreadToken(hHandle,
TOKEN_QUERY,
TRUE, // open as self
&hClientToken))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hHandle);
hHandle = NULL;
}
}
if(hr != S_OK)
{
hHandle = GetCurrentProcess();
if (NULL == hHandle)
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
else
{
HANDLE hProcessToken = NULL;
hr = S_OK;
if (!OpenProcessToken(hHandle,
TOKEN_DUPLICATE,
&hProcessToken))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hHandle);
hHandle = NULL;
}
else
{
if(!DuplicateToken(hProcessToken,
SecurityImpersonation,
&hClientToken))
{
hr = HRESULT_FROM_WIN32(GetLastError());
CloseHandle(hHandle);
hHandle = NULL;
}
CloseHandle(hProcessToken);
}
}
}
if(hr == S_OK)
{
hr = CAAccessCheck(
hCAInfo,
hClientToken);
CloseHandle(hClientToken);
}
if(hHandle)
{
CloseHandle(hHandle);
}
return (S_OK == hr);
}
//--------------------------------------------------------------------
//
// TokenCheckCAPermission
//
//--------------------------------------------------------------------
BOOL TokenCheckCAPermission(HANDLE hToken, HCAINFO hCAInfo)
{
HRESULT hr=E_FAIL;
if(hToken)
{
hr = CAAccessCheck(
hCAInfo,
hToken);
return (S_OK == hr);
}
return CheckCAPermission(hCAInfo);
}
//--------------------------------------------------------------------
//
// CheckSubjectRequirement
//
//--------------------------------------------------------------------
/*BOOL CheckSubjectRequirement(HCERTTYPE hCurCertType)
{
DWORD dwFlags=0;
//check the subject requirement of the cert type
if(S_OK != CAGetCertTypeFlags(hCurCertType, &dwFlags))
return FALSE;
if(CT_FLAG_IS_SUBJECT_REQ & dwFlags)
return FALSE;
return TRUE;
} */
//-----------------------------------------------------------------------
//
// GetCAProperties
//
//------------------------------------------------------------------------
BOOL GetCAProperties(HCAINFO hCurCAInfo,
SCrdEnroll_CA_INFO *pCAInfo)
{
BOOL fResult=FALSE;
DWORD errBefore= GetLastError();
HRESULT hr=S_OK;
LPWSTR *ppwszNameProp=NULL;
LPWSTR *ppwszLocationProp=NULL;
LPWSTR *ppwszDisplayNameProp=NULL;
//get the CAName
hr=CAGetCAProperty(
hCurCAInfo,
CA_PROP_NAME,
&ppwszNameProp);
if((S_OK != hr) || (NULL==ppwszNameProp))
{
if(!FAILED(hr))
hr=E_FAIL;
goto CertCliErr;
}
pCAInfo->pwszCAName=CopyWideString(ppwszNameProp[0]);
if(NULL == pCAInfo->pwszCAName)
goto MemoryErr;
//get the CADisplayName
hr=CAGetCAProperty(
hCurCAInfo,
CA_PROP_DISPLAY_NAME,
&ppwszDisplayNameProp);
if((S_OK != hr) || (NULL==ppwszDisplayNameProp))
{
if(!FAILED(hr))
hr=E_FAIL;
goto CertCliErr;
}
pCAInfo->pwszCADisplayName=CopyWideString(ppwszDisplayNameProp[0]);
if(NULL == pCAInfo->pwszCADisplayName)
goto MemoryErr;
//get the CA location
hr=CAGetCAProperty(
hCurCAInfo,
CA_PROP_DNSNAME,
&ppwszLocationProp);
if((S_OK != hr) || (NULL==ppwszLocationProp))
{
if(!FAILED(hr))
hr=E_FAIL;
goto CertCliErr;
}
//copy the name
pCAInfo->pwszCALocation=CopyWideString(ppwszLocationProp[0]);
if(NULL == pCAInfo->pwszCALocation)
goto MemoryErr;
fResult=TRUE;
CommonReturn:
if(ppwszNameProp)
CAFreeCAProperty(hCurCAInfo, ppwszNameProp);
if(ppwszLocationProp)
CAFreeCAProperty(hCurCAInfo, ppwszLocationProp);
if(ppwszDisplayNameProp)
CAFreeCAProperty(hCurCAInfo, ppwszDisplayNameProp);
SetLastError(errBefore);
return fResult;
ErrorReturn:
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
//in error case, free the memory and memset to 0
if(pCAInfo)
FreeCAInfoElement(pCAInfo);
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
SET_ERROR_VAR(CertCliErr, hr);
}
//-----------------------------------------------------------------------
//
// GetCAInfoFromCertType
//
//------------------------------------------------------------------------
BOOL GetCAInfoFromCertType(HANDLE hToken,
LPWSTR pwszCTName,
DWORD *pdwValidCA,
SCrdEnroll_CA_INFO **prgCAInfo)
{
BOOL fResult=FALSE;
HRESULT hr=S_OK;
DWORD errBefore= GetLastError();
DWORD dwCACount=0;
DWORD dwValidCA=0;
SCrdEnroll_CA_INFO *rgCAInfo=NULL;
HCAINFO hCurCAInfo=NULL;
HCAINFO hPreCAInfo=NULL;
//init
*pdwValidCA=0;
*prgCAInfo=NULL;
if(NULL == pwszCTName)
goto InvalidArgErr;
hr = CAFindByCertType(
pwszCTName,
NULL,
0,
&hCurCAInfo);
if( hr!=S_OK || NULL==hCurCAInfo)
{
if(S_OK == hr)
hr=E_FAIL;
goto CertCliErr;
}
//get the CA count
dwCACount=CACountCAs(hCurCAInfo);
if(0==dwCACount)
{
hr=E_FAIL;
goto CertCliErr;
}
//allocate memory
rgCAInfo=(SCrdEnroll_CA_INFO *)SCrdEnrollAlloc(dwCACount *
sizeof(SCrdEnroll_CA_INFO));
if(NULL == rgCAInfo)
goto MemoryErr;
memset(rgCAInfo, 0, dwCACount * sizeof(SCrdEnroll_CA_INFO));
dwValidCA=0;
while(hCurCAInfo)
{
//get the CA information
if(TokenCheckCAPermission(hToken, hCurCAInfo))
{
if(GetCAProperties(hCurCAInfo, &(rgCAInfo[dwValidCA])))
{
//increment the count
dwValidCA++;
}
}
//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;
}
if( (0 == dwValidCA) || (NULL == rgCAInfo))
{
hr=E_FAIL;
goto CertCliErr;
}
//copy the output data
*pdwValidCA=dwValidCA;
*prgCAInfo=rgCAInfo;
fResult=TRUE;
CommonReturn:
if(hPreCAInfo)
CACloseCA(hPreCAInfo);
if(hCurCAInfo)
CACloseCA(hCurCAInfo);
SetLastError(errBefore);
return fResult;
ErrorReturn:
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
if(rgCAInfo)
FreeCAInfo(dwValidCA, rgCAInfo);
//NULL the output
*pdwValidCA=0;
*prgCAInfo=NULL;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
SET_ERROR_VAR(CertCliErr, hr);
SET_ERROR(InvalidArgErr, E_INVALIDARG);
}
//-----------------------------------------------------------------------
//
// InitializeCTList
//
//------------------------------------------------------------------------
BOOL InitializeCTList(DWORD *pdwCTIndex,
DWORD *pdwCTCount,
SCrdEnroll_CT_INFO **prgCTInfo)
{
BOOL fResult=FALSE;
HRESULT hr=S_OK;
DWORD errBefore= GetLastError();
HCERTTYPE hCurCertType=NULL;
HCERTTYPE hPreCertType=NULL;
DWORD dwCertTypeCount=0;
DWORD dwIndex=0;
DWORD dwValidCertType=0;
SCrdEnroll_CT_INFO * rgCTInfo=NULL;
HANDLE hThread=NULL; //no need to close
HANDLE hToken=NULL;
*pdwCTIndex=0;
*pdwCTCount=0;
*prgCTInfo=NULL;
//first of all, we need to revert to ourselves if we are under impersonation
hThread=GetCurrentThread();
if(NULL != hThread)
{
if(OpenThreadToken(hThread,
TOKEN_IMPERSONATE | TOKEN_QUERY,
FALSE,
&hToken))
{
if(hToken)
{
//no need to check for return here. If this failed, just go on
RevertToSelf();
}
}
}
//get the 1st CT, including both machine and user cert types
hr=CAEnumCertTypes(CT_ENUM_USER_TYPES | CT_ENUM_MACHINE_TYPES, &hCurCertType);
if((S_OK != hr) || (NULL==hCurCertType))
{
if(S_OK != hr)
hr=E_FAIL;
goto CertCliErr;
}
//get the count of the cert types supported by this CA
dwCertTypeCount=CACountCertTypes(hCurCertType);
if(0==dwCertTypeCount)
{
hr=E_FAIL;
goto CertCliErr;
}
//allocate memory
rgCTInfo=(SCrdEnroll_CT_INFO *)SCrdEnrollAlloc(dwCertTypeCount *
sizeof(SCrdEnroll_CT_INFO));
if(NULL == rgCTInfo)
goto MemoryErr;
memset(rgCTInfo, 0, dwCertTypeCount * sizeof(SCrdEnroll_CT_INFO));
dwValidCertType = 0;
while(hCurCertType)
{
if(TokenCheckAccessPermission(hToken, hCurCertType) &&
GetCertTypeProperties(hCurCertType, &(rgCTInfo[dwValidCertType]))
)
{
dwValidCertType++;
}
//enum for the next cert types
hPreCertType=hCurCertType;
hr=CAEnumNextCertType(
hPreCertType,
&hCurCertType);
//free the old cert type
CACloseCertType(hPreCertType);
hPreCertType=NULL;
if((S_OK != hr) || (NULL==hCurCertType))
break;
}
//now that we have find all the cert types, we need to find one cert
//that has the associated CA information
//if hToken, we are running as the certserv's ASP pages. We need to retrieve all the
// CA's information since we are in the revert to self mode.
if(NULL == hToken)
{
for(dwIndex=0; dwIndex < dwValidCertType; dwIndex++)
{
//we do not consider the machine cert types
if(TRUE == rgCTInfo[dwIndex].fMachine)
continue;
//mark that we have queried the CA information of the
//certType
rgCTInfo[dwIndex].fCAInfo=TRUE;
if(GetCAInfoFromCertType(NULL,
rgCTInfo[dwIndex].pwszCTName,
&(rgCTInfo[dwIndex].dwCACount),
&(rgCTInfo[dwIndex].rgCAInfo)))
break;
}
if(dwIndex == dwValidCertType)
{
hr=E_FAIL;
goto CertCliErr;
}
}
else
{
for(dwIndex=0; dwIndex < dwValidCertType; dwIndex++)
{
//mark that we have queried the CA information of the
//certType
rgCTInfo[dwIndex].fCAInfo=TRUE;
GetCAInfoFromCertType( hToken,
rgCTInfo[dwIndex].pwszCTName,
&(rgCTInfo[dwIndex].dwCACount),
&(rgCTInfo[dwIndex].rgCAInfo));
}
}
if((0 == dwValidCertType) || (NULL == rgCTInfo))
{
hr=E_FAIL;
goto CertCliErr;
}
*pdwCTIndex=dwIndex;
*pdwCTCount=dwValidCertType;
*prgCTInfo=rgCTInfo;
fResult=TRUE;
CommonReturn:
if(hPreCertType)
CACloseCertType(hPreCertType);
if(hCurCertType)
CACloseCertType(hCurCertType);
//if hToken is valid, we reverted to ourselves.
if(hToken)
{
SetThreadToken(&hThread, hToken);
CloseHandle(hToken);
}
SetLastError(errBefore);
return fResult;
ErrorReturn:
if(ERROR_SUCCESS == (errBefore = GetLastError()))
errBefore=E_UNEXPECTED;
//free all the memory
if(rgCTInfo)
FreeCTInfo(dwValidCertType, rgCTInfo);
//NULL the output
*pdwCTIndex=0;
*pdwCTCount=0;
*prgCTInfo=NULL;
goto CommonReturn;
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
SET_ERROR_VAR(CertCliErr, hr);
}
//-----------------------------------------------------------------------
//
// RetrieveCAName
//
//------------------------------------------------------------------------
BOOL RetrieveCAName(DWORD dwFlags,
SCrdEnroll_CA_INFO *pCAInfo,
LPWSTR *ppwszName)
{
DWORD dwSize = 0;
BOOL fResult=FALSE;
if(NULL == ppwszName)
goto InvalidArgErr;
if(dwFlags == SCARD_ENROLL_CA_MACHINE_NAME)
*ppwszName = CopyWideString(pCAInfo->pwszCALocation);
else
{
if(dwFlags == SCARD_ENROLL_CA_DISPLAY_NAME)
*ppwszName = CopyWideString(pCAInfo->pwszCADisplayName);
else
{
if(dwFlags == SCARD_ENROLL_CA_UNIQUE_NAME)
{
dwSize = wcslen(pCAInfo->pwszCALocation) + wcslen(pCAInfo->pwszCADisplayName) + wcslen(L"\\") + 2;
*ppwszName = (LPWSTR)SCrdEnrollAlloc(sizeof(WCHAR) * dwSize);
if(NULL == (*ppwszName))
goto MemoryErr;
wcscpy(*ppwszName, pCAInfo->pwszCALocation);
wcscat(*ppwszName, L"\\");
wcscat(*ppwszName, pCAInfo->pwszCADisplayName);
}
else
*ppwszName = CopyWideString(pCAInfo->pwszCAName);
}
}
if(NULL == (*ppwszName))
goto MemoryErr;
fResult=TRUE;
CommonReturn:
return fResult;
ErrorReturn:
fResult=FALSE;
goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG);
SET_ERROR(MemoryErr, E_OUTOFMEMORY);
}