|
|
//+---------------------------------------------------------------------------
//
// 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); }
|