|
|
//--------------------------------------------------------------
// Copyright (C) Microsoft Corporation, 1996 - 1999
//
// File: wizards.cpp
//
// Contents: The cpp file to implement the wizards
//
// History: 16-10-1997 xiaohs created
//
//--------------------------------------------------------------
#include "wzrdpvk.h"
#include "certca.h"
#include "cautil.h"
#include "CertRequesterContext.h"
#include "CertDSManager.h"
#include "CertRequester.h"
//need the CLSID and IID for xEnroll
#include <ole2.h>
#include <oleauto.h>
#include "xenroll.h"
#include "xenroll_i.c"
#include <certrpc.h>
#define _SET_XENROLL_PROPERTY_IF(condition, property, arg) \
{ \ if ( condition ) { \ if (S_OK != (hr = pIEnroll->put_ ## property ( arg ))) \ goto xEnrollErr; \ } \ }
// Used to provide singleton instances of useful COM objects in a demand-driven fashion.
// See wzrdpvk.h.
extern EnrollmentCOMObjectFactory *g_pEnrollFactory;
extern HMODULE g_hmodRichEdit; extern HMODULE g_hmodxEnroll;
typedef struct _CERT_ACCEPT_INFO { PCCERT_CONTEXT pCertContext; PCRYPT_DATA_BLOB pPKCS7Blob; LPWSTR pwszTitle; }CERT_ACCEPT_INFO; #define USE_NP
typedef struct _CREATE_REQUEST_WIZARD_STATE { BOOL fMustFreeRequestBlob; CRYPT_DATA_BLOB RequestBlob; CRYPT_DATA_BLOB HashBlob; DWORD dwMyStoreFlags; DWORD dwRootStoreFlags; LPWSTR pwszMyStoreName; LPWSTR pwszRootStoreName; LONG lRequestFlags; BOOL fReusedPrivateKey; BOOL fNewKey; } CREATE_REQUEST_WIZARD_STATE, *PCREATE_REQUEST_WIZARD_STATE;
typedef IEnroll4 * (WINAPI *PFNPIEnroll4GetNoCOM)();
BOOL CertAllocAndGetCertificateContextProperty (IN PCCERT_CONTEXT pCertContext, IN DWORD dwPropID, OUT void **ppvData, OUT DWORD *pcbData) { if (NULL == ppvData || NULL == pcbData) return FALSE;
*ppvData = 0; *pcbData = 0;
if(!CertGetCertificateContextProperty (pCertContext, dwPropID, NULL, pcbData) || (0==*pcbData)) return FALSE; *ppvData = WizardAlloc(*pcbData); if(NULL == *ppvData) return FALSE;
if(!CertGetCertificateContextProperty (pCertContext, dwPropID, *ppvData, pcbData)) return FALSE;
return TRUE; }
/*typedef HRESULT (WINAPI *pfDllGetClassObject)(REFCLSID rclsid,
REFIID riid, LPVOID *ppvOut); */ //////////////////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////////////////
//------------------------------------------------------------------------------
// WizGetOpenFileName
//----------------------------------------------------------------------------
BOOL WizGetOpenFileName(LPOPENFILENAMEW pOpenFileName) {
BOOL fResult=FALSE;
__try {
fResult=GetOpenFileNameU(pOpenFileName);
} __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(GetExceptionCode()); fResult=FALSE; }
return fResult; }
//------------------------------------------------------------------------------
// WizGetSaveFileName
//----------------------------------------------------------------------------
BOOL WizGetSaveFileName(LPOPENFILENAMEW pOpenFileName) {
BOOL fResult=FALSE;
__try {
fResult=GetSaveFileNameU(pOpenFileName);
} __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(GetExceptionCode()); fResult=FALSE; }
return fResult; }
void FreeProviders( DWORD dwCSPCount, DWORD *rgdwProviderType, LPWSTR *rgwszProvider) { //free the rgdwProviderType and rgwszProvider;
if(NULL != rgdwProviderType) { WizardFree(rgdwProviderType); }
if(NULL != rgwszProvider) { for(DWORD dwIndex=0; dwIndex<dwCSPCount; dwIndex++) { if (NULL != rgwszProvider[dwIndex]) { WizardFree(rgwszProvider[dwIndex]); } } WizardFree(rgwszProvider); } }
//------------------------------------------------------------------------------
// Unicode version of CB_GETLBTEXT
//----------------------------------------------------------------------------
LRESULT WINAPI SendDlgItemMessageU_GETLBTEXT ( HWND hwndDlg, int nIDDlgItem, int iIndex, LPWSTR *ppwsz ) { LPSTR sz = NULL; LPWSTR pwsz=NULL; LRESULT lRet; int iLength=0;
iLength=(int)SendDlgItemMessage(hwndDlg, nIDDlgItem, CB_GETLBTEXTLEN, iIndex, 0);
if(iLength == CB_ERR) return CB_ERR;
if(FIsWinNT()) { *ppwsz=(LPWSTR)WizardAlloc(sizeof(WCHAR) * (iLength + 1));
if(NULL == (*ppwsz)) return CB_ERR;
lRet = SendDlgItemMessageW( hwndDlg, nIDDlgItem, CB_GETLBTEXT, iIndex, (LPARAM) (*ppwsz) );
if(CB_ERR == lRet) { WizardFree(*ppwsz); *ppwsz=NULL; }
return lRet; }
sz=(LPSTR)WizardAlloc(sizeof(CHAR) * (iLength + 1));
if(NULL == sz) return CB_ERR;
lRet = SendDlgItemMessageA( hwndDlg, nIDDlgItem, CB_GETLBTEXT, iIndex, (LPARAM)sz );
if(CB_ERR == lRet) goto CLEANUP;
if(NULL == (pwsz=MkWStr(sz))) { lRet=CB_ERR; goto CLEANUP; }
*ppwsz=WizardAllocAndCopyWStr(pwsz);
if(NULL == (*ppwsz)) { lRet=CB_ERR; goto CLEANUP; }
CLEANUP:
if(sz) WizardFree(sz);
if(pwsz) FreeWStr(pwsz);
return (lRet); }
//
// A mapping from cert type flags to gen key flags.
//
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 }, { CT_FLAG_STRONG_KEY_PROTECTION_REQUIRED, CRYPT_USER_PROTECTED } }; 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; }
HRESULT GetCAExchangeCertificate(IN BSTR bstrCAQualifiedName, OUT PCCERT_CONTEXT *ppCert) { HRESULT hr = S_OK;
// BUGBUG: need to use global enrollment factory.
EnrollmentCOMObjectFactory *pEnrollFactory = NULL; ICertRequest2 *pCertRequest = NULL; VARIANT varExchangeCertificate;
// We're using a COM component in this method. It's absolutely necessary that we
// uninitialize COM before we return, because we're running in an RPC thread,
// and failing to uninitialize COM will cause us to step on RPC's toes.
//
// See BUG 404778.
__try { // Input validation:
if (NULL == bstrCAQualifiedName || NULL == ppCert) return E_INVALIDARG;
// Init:
*ppCert = NULL; VariantInit(&varExchangeCertificate);
pEnrollFactory = new EnrollmentCOMObjectFactory; if (NULL == pEnrollFactory) { hr = E_OUTOFMEMORY; goto Error; }
if (S_OK != (hr = pEnrollFactory->getICertRequest2(&pCertRequest))) goto Error;
if (S_OK != (hr = pCertRequest->GetCAProperty (bstrCAQualifiedName, // CA Name/CA Location
CR_PROP_CAXCHGCERT, // Get the exchange certificate from the CA.
0, // Unused
PROPTYPE_BINARY, //
CR_OUT_BINARY, //
&varExchangeCertificate // Variant type representing the certificate.
))) goto Error; if (VT_BSTR != varExchangeCertificate.vt || NULL == varExchangeCertificate.bstrVal) { hr = E_UNEXPECTED; goto Error; }
*ppCert = CertCreateCertificateContext (X509_ASN_ENCODING, (LPBYTE)varExchangeCertificate.bstrVal, SysStringByteLen(varExchangeCertificate.bstrVal)); if (*ppCert == NULL) { hr = CodeToHR(GetLastError()); goto Error; } } __except (EXCEPTION_EXECUTE_HANDLER) { hr = GetExceptionCode(); goto Error; }
CommonReturn: if (NULL != pCertRequest) { pCertRequest->Release(); } if (NULL != pEnrollFactory) { delete pEnrollFactory; } VariantClear(&varExchangeCertificate); return hr; Error: if (ppCert != NULL && *ppCert != NULL) { CertFreeCertificateContext(*ppCert); *ppCert = NULL; } goto CommonReturn; }
HRESULT WizardSZToWSZ (IN LPCSTR psz, OUT LPWSTR *ppwsz) { HRESULT hr = S_OK; LONG cc = 0;
if (NULL == ppwsz) return E_INVALIDARG;
//init
*ppwsz = NULL;
cc = MultiByteToWideChar(GetACP(), 0, psz, -1, NULL, 0); if (0 == cc) goto Win32Err;
*ppwsz = (LPWSTR)WizardAlloc(sizeof (WCHAR) * cc); if (NULL == *ppwsz) goto MemoryErr;
cc = MultiByteToWideChar(GetACP(), 0, psz, -1, *ppwsz, cc); if (0 == cc) goto Win32Err;
CommonReturn: return hr;
ErrorReturn: if (NULL != ppwsz && NULL != *ppwsz) { WizardFree(*ppwsz); *ppwsz = NULL; }
goto CommonReturn;
SET_HRESULT(Win32Err, GetLastError()); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); }
//--------------------------------------------------------------------------
//
// WizardAllocAndCopyStr
//
//--------------------------------------------------------------------------
LPSTR WizardAllocAndCopyStr(LPSTR psz) { LPSTR pszReturn;
if (NULL == (pszReturn = (LPSTR) WizardAlloc((strlen(psz)+1) * sizeof(CHAR)))) { return NULL; } strcpy(pszReturn, psz);
return(pszReturn); }
//--------------------------------------------------------------------------
//
// WizardAllocAndConcatStrU
//
//--------------------------------------------------------------------------
LPWSTR WizardAllocAndConcatStrsU(LPWSTR * rgStrings, DWORD dwStringsLen) { DWORD cbReturn = 0; LPWSTR pwszReturn = NULL;
if (NULL == rgStrings) return NULL;
for (DWORD dwIndex = 0; dwIndex < dwStringsLen; dwIndex++) cbReturn += wcslen(rgStrings[dwIndex]);
// Add space for NULL character.
cbReturn = (cbReturn + 1) * sizeof(WCHAR);
if (NULL == (pwszReturn = (LPWSTR)WizardAlloc(cbReturn))) return NULL;
for (DWORD dwIndex = 0; dwIndex < dwStringsLen; dwIndex++) wcscat(pwszReturn, rgStrings[dwIndex]);
return (pwszReturn); }
//--------------------------------------------------------------------------
//
// InitUnicodeString
//
//--------------------------------------------------------------------------
void WizardInitUnicodeString(PKEYSVC_UNICODE_STRING pUnicodeString, LPCWSTR pszString ) { pUnicodeString->Length = (USHORT)(wcslen(pszString) * sizeof(WCHAR)); pUnicodeString->MaximumLength = pUnicodeString->Length + sizeof(WCHAR); pUnicodeString->Buffer = (USHORT*)pszString; }
//--------------------------------------------------------------------------
//
// SetControlFont
//
//--------------------------------------------------------------------------
void SetControlFont( IN HFONT hFont, IN HWND hwnd, IN INT nId ) { if( hFont ) { HWND hwndControl = GetDlgItem(hwnd, nId);
if( hwndControl ) { SetWindowFont(hwndControl, hFont, TRUE); } } }
//--------------------------------------------------------------------------
//
// SetupFonts
//
//--------------------------------------------------------------------------
BOOL SetupFonts( IN HINSTANCE hInstance, IN HWND hwnd, IN HFONT *pBigBoldFont, IN HFONT *pBoldFont ) { //
// Create the fonts we need based on the dialog font
//
NONCLIENTMETRICS ncm = {0}; ncm.cbSize = sizeof(ncm); if (!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) return FALSE;
LOGFONT BigBoldLogFont = ncm.lfMessageFont; LOGFONT BoldLogFont = ncm.lfMessageFont;
//
// Create Big Bold Font and Bold Font
//
BigBoldLogFont.lfWeight = FW_BOLD; BoldLogFont.lfWeight = FW_BOLD;
CHAR FontSizeString[24]; INT BigBoldFontSize; INT BoldFontSize;
//
// Load size and name from resources, since these may change
// from locale to locale based on the size of the system font, etc.
//
/*
//no longer needs to do it. We are loading the default font
if(!LoadStringA(hInstance,IDS_LARGEFONTNAME,BigBoldLogFont.lfFaceName,LF_FACESIZE)) { lstrcpy(BigBoldLogFont.lfFaceName,TEXT("MS Shell Dlg")); }
if(!LoadStringA(hInstance,IDS_BOLDFONTNAME,BoldLogFont.lfFaceName,LF_FACESIZE)) { lstrcpy(BoldLogFont.lfFaceName,TEXT("MS Sans Serif")); } */ if(LoadStringA(hInstance,IDS_LARGEFONTSIZE,FontSizeString,sizeof(FontSizeString))) { BigBoldFontSize = strtoul( FontSizeString, NULL, 10 ); } else { BigBoldFontSize = 12; }
if(LoadStringA(hInstance,IDS_BOLDFONTSIZE,FontSizeString,sizeof(FontSizeString))) { BoldFontSize = strtoul( FontSizeString, NULL, 10 ); } else { BoldFontSize = 8; }
HDC hdc = GetDC( hwnd );
if( hdc ) { BigBoldLogFont.lfHeight = 0 - (GetDeviceCaps(hdc,LOGPIXELSY) * BigBoldFontSize / 72); BoldLogFont.lfHeight = 0 - (GetDeviceCaps(hdc,LOGPIXELSY) * BoldFontSize / 72);
*pBigBoldFont = CreateFontIndirect(&BigBoldLogFont); *pBoldFont = CreateFontIndirect(&BoldLogFont);
ReleaseDC(hwnd,hdc);
if(*pBigBoldFont && *pBoldFont) return TRUE; else { if( *pBigBoldFont ) { DeleteObject(*pBigBoldFont); }
if( *pBoldFont ) { DeleteObject(*pBoldFont); } return FALSE; } }
return FALSE; }
//--------------------------------------------------------------------------
//
// DestroyFonts
//
//--------------------------------------------------------------------------
void DestroyFonts( IN HFONT hBigBoldFont, IN HFONT hBoldFont ) { if( hBigBoldFont ) { DeleteObject( hBigBoldFont ); }
if( hBoldFont ) { DeleteObject( hBoldFont ); } }
//-------------------------------------------------------------------------
//
// Unicode version of SendMessage
//
//-------------------------------------------------------------------------
LRESULT Send_LB_GETTEXT( HWND hwnd, WPARAM wParam, LPARAM lParam ) { int iLength=0; LPSTR psz=0; LRESULT lResult; BOOL fResult=FALSE;
if(FIsWinNT()) { return SendMessageW(hwnd, LB_GETTEXT, wParam, lParam);
}
//get the length of the buffer
iLength=(int)SendMessageA(hwnd, LB_GETTEXTLEN, wParam, 0);
psz=(LPSTR)WizardAlloc(iLength+1);
if(NULL==psz) return LB_ERR;
lResult=SendMessageA(hwnd, LB_GETTEXT, wParam, (LPARAM)psz);
if(LB_ERR==lResult) { WizardFree(psz); return LB_ERR; }
fResult=MultiByteToWideChar( 0, 0, psz, -1, (LPWSTR)lParam, iLength+1);
WizardFree(psz);
if(TRUE==fResult) return lResult; else return LB_ERR; }
//-------------------------------------------------------------------------
//
// Unicode version of SendMessage
//
//-------------------------------------------------------------------------
LRESULT Send_LB_ADDSTRING( HWND hwnd, WPARAM wParam, LPARAM lParam ) { LPSTR psz=NULL; LRESULT lResult;
if(FIsWinNT()) { return SendMessageW(hwnd, LB_ADDSTRING, wParam, lParam);
}
psz=(LPSTR)WizardAlloc(wcslen((LPWSTR)lParam)+1);
if(NULL==psz) return LB_ERRSPACE;
if(0==WideCharToMultiByte(0, 0, (LPWSTR)lParam, -1, psz, wcslen((LPWSTR)lParam)+1, NULL, NULL)) { WizardFree(psz); return LB_ERR; }
lResult=SendMessageA(hwnd, LB_ADDSTRING, wParam, (LPARAM)psz);
WizardFree(psz);
return lResult; }
//-----------------------------------------------------------------------
// Get the default CSP name based on the provider type
//
//------------------------------------------------------------------------
BOOL CSPSupported(CERT_WIZARD_INFO *pCertWizardInfo) { BOOL fResult=FALSE; DWORD dwIndex=0;
if(!pCertWizardInfo) goto InvalidArgErr;
if(!(pCertWizardInfo->dwProviderType) || !(pCertWizardInfo->pwszProvider)) goto InvalidArgErr;
for(dwIndex=0; dwIndex < pCertWizardInfo->dwCSPCount; dwIndex++) { if((pCertWizardInfo->dwProviderType == pCertWizardInfo->rgdwProviderType[dwIndex] ) && (0==_wcsicmp(pCertWizardInfo->pwszProvider, pCertWizardInfo->rgwszProvider[dwIndex])) ) { fResult=TRUE; break; } }
CommonReturn:
return fResult;
ErrorReturn: fResult=FALSE; goto CommonReturn;
SET_ERROR(InvalidArgErr, E_INVALIDARG); }
//-----------------------------------------------------------------------
// Get a list of allowed CAs
//
//------------------------------------------------------------------------
BOOL GetCAName(CERT_WIZARD_INFO *pCertWizardInfo) { DWORD dwErr=0; KEYSVC_TYPE dwServiceType=KeySvcMachine; KEYSVCC_HANDLE hKeyService=NULL; PKEYSVC_UNICODE_STRING pCA = NULL; DWORD cCA=0; LPSTR pszMachineName=NULL; DWORD cbArray = 0; DWORD i=0; LPWSTR wszCurrentCA=NULL; BOOL fResult=FALSE; // We're not doing a local enrollment, so we must enroll via keysvc. Get the
// list of acceptable cert types.
if(pCertWizardInfo->pwszAccountName) dwServiceType=KeySvcService; else dwServiceType=KeySvcMachine;
if(!MkMBStr(NULL, 0, pCertWizardInfo->pwszMachineName, &pszMachineName)) goto TraceErr; dwErr = KeyOpenKeyService(pszMachineName, dwServiceType, (LPWSTR)(pCertWizardInfo->pwszAccountName), NULL, // no authentication string right now
NULL, &hKeyService); if(dwErr != ERROR_SUCCESS) { SetLastError(dwErr); goto TraceErr; }
dwErr = KeyEnumerateCAs(hKeyService, NULL, CA_FIND_LOCAL_SYSTEM, &cCA, &pCA); if(dwErr != ERROR_SUCCESS) { SetLastError(dwErr); goto TraceErr; }
cbArray = (cCA+1)*sizeof(LPWSTR);
// Convert into a simple array
for(i=0; i < cCA; i++) { cbArray += pCA[i].Length; }
pCertWizardInfo->awszValidCA = (LPWSTR *)WizardAlloc(cbArray);
if(pCertWizardInfo->awszValidCA == NULL) goto MemoryErr;
memset(pCertWizardInfo->awszValidCA, 0, cbArray);
wszCurrentCA = (LPWSTR)(&((pCertWizardInfo->awszValidCA)[cCA + 1])); for(i=0; i < cCA; i++) { (pCertWizardInfo->awszValidCA)[i] = wszCurrentCA;
wcscpy(wszCurrentCA, pCA[i].Buffer);
wszCurrentCA += wcslen(wszCurrentCA)+1; }
fResult=TRUE;
CommonReturn:
if(pCA) WizardFree(pCA);
if(hKeyService) KeyCloseKeyService(hKeyService, NULL);
if(pszMachineName) FreeMBStr(NULL,pszMachineName);
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
TRACE_ERROR(TraceErr); SET_ERROR(MemoryErr, E_OUTOFMEMORY); }
//-----------------------------------------------------------------------
// Get a list of allowed cert types
//
//------------------------------------------------------------------------
BOOL GetCertTypeName(CERT_WIZARD_INFO *pCertWizardInfo) { DWORD dwErr=0; KEYSVC_TYPE dwServiceType=KeySvcMachine; KEYSVCC_HANDLE hKeyService=NULL; PKEYSVC_UNICODE_STRING pCertTypes = NULL; DWORD cTypes=0; LPSTR pszMachineName=NULL; DWORD cbArray = 0; DWORD i=0; LPWSTR wszCurrentType; BOOL fResult=FALSE; // We're not doing a local enrollment, so we must enroll via keysvc. Get the
// list of acceptable cert types.
if(pCertWizardInfo->pwszAccountName) dwServiceType=KeySvcService; else dwServiceType=KeySvcMachine;
if(!MkMBStr(NULL, 0, pCertWizardInfo->pwszMachineName, &pszMachineName)) goto TraceErr; dwErr = KeyOpenKeyService(pszMachineName, dwServiceType, (LPWSTR)(pCertWizardInfo->pwszAccountName), 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; }
pCertWizardInfo->awszAllowedCertTypes = (LPWSTR *)WizardAlloc(cbArray);
if(pCertWizardInfo->awszAllowedCertTypes == NULL) goto MemoryErr;
memset(pCertWizardInfo->awszAllowedCertTypes, 0, cbArray);
wszCurrentType = (LPWSTR)(&((pCertWizardInfo->awszAllowedCertTypes)[cTypes + 1])); for(i=0; i < cTypes; i++) { (pCertWizardInfo->awszAllowedCertTypes)[i] = wszCurrentType;
wcscpy(wszCurrentType, pCertTypes[i].Buffer);
wszCurrentType += wcslen(wszCurrentType)+1; }
fResult=TRUE;
CommonReturn:
if(pCertTypes) WizardFree(pCertTypes);
if(hKeyService) KeyCloseKeyService(hKeyService, NULL);
if(pszMachineName) FreeMBStr(NULL,pszMachineName);
return fResult;
ErrorReturn:
fResult=FALSE; goto CommonReturn;
TRACE_ERROR(TraceErr); SET_ERROR(MemoryErr, E_OUTOFMEMORY); }
//-----------------------------------------------------------------------
// WizardInit
//------------------------------------------------------------------------
BOOL WizardInit(BOOL fLoadRichEdit) { if ((fLoadRichEdit) && (g_hmodRichEdit == NULL)) { g_hmodRichEdit = LoadLibraryA("RichEd32.dll"); if (g_hmodRichEdit == NULL) { return FALSE; } }
INITCOMMONCONTROLSEX initcomm = { sizeof(initcomm), ICC_NATIVEFNTCTL_CLASS | ICC_LISTVIEW_CLASSES };
InitCommonControlsEx(&initcomm);
return TRUE; }
//-----------------------------------------------------------------------
//check for the private key information
//-----------------------------------------------------------------------
BOOL CheckPVKInfoNoDS(DWORD /*dwFlags*/, DWORD dwPvkChoice, PCCRYPTUI_WIZ_CERT_REQUEST_PVK_CERT pCertRequestPvkContext, PCCRYPTUI_WIZ_CERT_REQUEST_PVK_NEW pCertRequestPvkNew, PCCRYPTUI_WIZ_CERT_REQUEST_PVK_EXISTING pCertRequestPvkExisting, DWORD dwCertChoice, CERT_WIZARD_INFO *pCertWizardInfo, CRYPT_KEY_PROV_INFO **ppKeyProvInfo) { DWORD cbData = 0; BOOL fResult = FALSE;
pCertWizardInfo->fIgnore=FALSE;
//check if we need to generate a new private key
switch(dwPvkChoice) { case CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_CERT:
if (sizeof(CRYPTUI_WIZ_CERT_REQUEST_PVK_CERT) != pCertRequestPvkContext->dwSize) return FALSE;
if(NULL==pCertRequestPvkContext->pCertContext) return FALSE;
//pCertContext should have a property of CRYPT_KEY_PROV_INFO
if(!CertAllocAndGetCertificateContextProperty (pCertRequestPvkContext->pCertContext, CERT_KEY_PROV_INFO_PROP_ID, (LPVOID *)ppKeyProvInfo, &cbData)) goto CLEANUP;
pCertWizardInfo->fNewKey = FALSE; pCertWizardInfo->dwProviderType = (*ppKeyProvInfo)->dwProvType; pCertWizardInfo->pwszProvider = (*ppKeyProvInfo)->pwszProvName; pCertWizardInfo->dwProviderFlags = (*ppKeyProvInfo)->dwFlags; pCertWizardInfo->pwszKeyContainer = (*ppKeyProvInfo)->pwszContainerName; pCertWizardInfo->dwKeySpec = (*ppKeyProvInfo)->dwKeySpec; break;
case CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_NEW:
//check the size of the struct
if(pCertRequestPvkNew->dwSize!=sizeof(CRYPTUI_WIZ_CERT_REQUEST_PVK_NEW)) goto CLEANUP; pCertWizardInfo->fNewKey=TRUE; //we only copy the information if:
//1. Cert type is required
//2. The CSP is specified
if((CRYPTUI_WIZ_CERT_REQUEST_CERT_TYPE == dwCertChoice) || (0 == dwCertChoice)) { if(pCertRequestPvkNew->pKeyProvInfo) { if( (0 == pCertRequestPvkNew->pKeyProvInfo->dwProvType) && (NULL == (LPWSTR)(pCertRequestPvkNew->pKeyProvInfo->pwszProvName)) ) pCertWizardInfo->fIgnore=TRUE; } else pCertWizardInfo->fIgnore=TRUE; }
//see if pKeyProvInfo is not NULL
if(pCertRequestPvkNew->pKeyProvInfo) { if(TRUE == pCertWizardInfo->fIgnore) { pCertWizardInfo->pwszKeyContainer =pCertRequestPvkNew->pKeyProvInfo->pwszContainerName; pCertWizardInfo->dwProviderFlags =pCertRequestPvkNew->pKeyProvInfo->dwFlags; } else { pCertWizardInfo->dwProviderType =pCertRequestPvkNew->pKeyProvInfo->dwProvType; pCertWizardInfo->pwszProvider =(LPWSTR)(pCertRequestPvkNew->pKeyProvInfo->pwszProvName); pCertWizardInfo->dwProviderFlags =pCertRequestPvkNew->pKeyProvInfo->dwFlags; pCertWizardInfo->pwszKeyContainer =pCertRequestPvkNew->pKeyProvInfo->pwszContainerName; pCertWizardInfo->dwKeySpec =pCertRequestPvkNew->pKeyProvInfo->dwKeySpec; } }
if(TRUE == pCertWizardInfo->fIgnore) //we should ignore the exportable flag
pCertWizardInfo->dwGenKeyFlags=(pCertRequestPvkNew->dwGenKeyFlags & (~CRYPT_EXPORTABLE)); else pCertWizardInfo->dwGenKeyFlags=pCertRequestPvkNew->dwGenKeyFlags; break; case CRYPTUI_WIZ_CERT_REQUEST_PVK_CHOICE_EXISTING: //check the size of the struct
if(pCertRequestPvkExisting->dwSize!=sizeof(CRYPTUI_WIZ_CERT_REQUEST_PVK_EXISTING)) goto CLEANUP;
pCertWizardInfo->fNewKey=FALSE;
//make sure pKeyProvInfo is not NULL
if(NULL==pCertRequestPvkExisting->pKeyProvInfo) goto CLEANUP; pCertWizardInfo->dwProviderType =pCertRequestPvkExisting->pKeyProvInfo->dwProvType; pCertWizardInfo->pwszProvider =(LPWSTR)(pCertRequestPvkExisting->pKeyProvInfo->pwszProvName); pCertWizardInfo->dwProviderFlags =pCertRequestPvkExisting->pKeyProvInfo->dwFlags; pCertWizardInfo->pwszKeyContainer =pCertRequestPvkExisting->pKeyProvInfo->pwszContainerName; pCertWizardInfo->dwKeySpec =pCertRequestPvkExisting->pKeyProvInfo->dwKeySpec; break; default: goto CLEANUP; break; }
//for existing keys, keyContainer and providerType has to set
if(FALSE==pCertWizardInfo->fNewKey) { if(NULL==pCertWizardInfo->pwszKeyContainer) goto CLEANUP;
if(0==pCertWizardInfo->dwProviderType) goto CLEANUP; }
//if the provider name is set, the provider type has to be set
if(0 == pCertWizardInfo->dwProviderType) { if(pCertWizardInfo->pwszProvider) goto CLEANUP; }
fResult=TRUE;
CLEANUP:
if(FALSE==fResult) { if(*ppKeyProvInfo) { WizardFree(*ppKeyProvInfo); *ppKeyProvInfo=NULL; } }
return fResult;
} BOOL CheckPVKInfo( DWORD dwFlags, PCCRYPTUI_WIZ_CERT_REQUEST_INFO pCertRequestInfo, CERT_WIZARD_INFO *pCertWizardInfo, CRYPT_KEY_PROV_INFO **ppKeyProvInfo) { if(NULL == pCertRequestInfo) return FALSE;
return CheckPVKInfoNoDS (dwFlags, pCertRequestInfo->dwPvkChoice, pCertRequestInfo->pPvkCert, pCertRequestInfo->pPvkNew, pCertRequestInfo->pPvkExisting, pCertRequestInfo->dwCertChoice, pCertWizardInfo, ppKeyProvInfo); }
//-----------------------------------------------------------------------
// Reset properties on the old certiifcate to the new certificat context
//------------------------------------------------------------------------
void ResetProperties(PCCERT_CONTEXT pOldCertContext, PCCERT_CONTEXT pNewCertContext) {
DWORD rgProperties[2]={CERT_FRIENDLY_NAME_PROP_ID, CERT_DESCRIPTION_PROP_ID};
DWORD cbData=0; BYTE *pbData=NULL; DWORD dwCount=sizeof(rgProperties)/sizeof(rgProperties[0]); DWORD dwIndex=0;
if(NULL==pOldCertContext || NULL==pNewCertContext) return;
//set the properies one at a time
for(dwIndex=0; dwIndex<dwCount; dwIndex++) { if (CertAllocAndGetCertificateContextProperty (pOldCertContext, rgProperties[dwIndex], (LPVOID *)&pbData, &cbData)) { CertSetCertificateContextProperty (pNewCertContext, rgProperties[dwIndex], 0, pbData); } WizardFree(pbData); pbData=NULL; }
if(pbData) WizardFree(pbData);
return;
}
//-----------------------------------------------------------------------
// Private implementation of the message box
//------------------------------------------------------------------------
int I_MessageBox( HWND hWnd, UINT idsText, UINT idsCaption, LPCWSTR pwszCaption, UINT uType ) {
WCHAR wszText[MAX_STRING_SIZE]; WCHAR wszCaption[MAX_STRING_SIZE]; UINT intReturn=0;
//get the caption string
if(NULL == pwszCaption) { if(!LoadStringU(g_hmodThisDll, idsCaption, wszCaption, ARRAYSIZE(wszCaption))) return 0;
pwszCaption = wszCaption; }
//get the text string
if(!LoadStringU(g_hmodThisDll, idsText, wszText, ARRAYSIZE(wszText))) { return 0; }
intReturn=MessageBoxExW(hWnd, wszText, pwszCaption, uType, 0);
return intReturn;
} //-----------------------------------------------------------------------
//
// CodeToHR
//
//------------------------------------------------------------------------
HRESULT CodeToHR(HRESULT hr) { if (S_OK != (DWORD) hr && S_FALSE != (DWORD) hr && (!FAILED(hr) || 0 == HRESULT_FACILITY(hr))) { hr = HRESULT_FROM_WIN32(hr); if (0 == HRESULT_CODE(hr)) { // A call failed without properly setting an error condition!
hr = E_UNEXPECTED; } } return(hr); }
//-----------------------------------------------------------------------
//
// CAUtilAddSMIME
//
//------------------------------------------------------------------------
BOOL CAUtilAddSMIME(DWORD dwExtensions, PCERT_EXTENSIONS *prgExtensions) { BOOL fSMIME = FALSE; DWORD dwIndex = 0; DWORD dwExt = 0; PCERT_EXTENSION pExt = NULL; DWORD cb = 0; DWORD dwUsage = 0; CERT_ENHKEY_USAGE *pUsage = NULL; for(dwIndex=0; dwIndex < dwExtensions; dwIndex++) { for(dwExt=0; dwExt < prgExtensions[dwIndex]->cExtension; dwExt++) { pExt=&(prgExtensions[dwIndex]->rgExtension[dwExt]);
if(0==_stricmp(szOID_ENHANCED_KEY_USAGE, pExt->pszObjId)) { if(!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, pExt->Value.pbData, pExt->Value.cbData, 0, NULL, &cb)) goto CLEANUP;
pUsage=(CERT_ENHKEY_USAGE *)WizardAlloc(cb); if(NULL==pUsage) goto CLEANUP;
if(!CryptDecodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, X509_ENHANCED_KEY_USAGE, pExt->Value.pbData, pExt->Value.cbData, 0, pUsage, &cb)) goto CLEANUP;
for(dwUsage=0; dwUsage<pUsage->cUsageIdentifier; dwUsage++) { if(0==_stricmp(szOID_PKIX_KP_EMAIL_PROTECTION, pUsage->rgpszUsageIdentifier[dwUsage])) { fSMIME=TRUE; goto CLEANUP; } }
if(pUsage) { WizardFree(pUsage); pUsage=NULL; }
} } }
CLEANUP:
if(pUsage) WizardFree(pUsage);
return fSMIME; } //-----------------------------------------------------------------------
//
// The following are memory routines for certdg_c.c
//------------------------------------------------------------------------
void* MIDL_user_allocate(size_t cb) { return(WizardAlloc(cb)); }
void MIDL_user_free(void *pb) { WizardFree(pb); }
//-----------------------------------------------------------------------
//
// CanUse1024BitKey
//
//------------------------------------------------------------------------
BOOL CanUse1024BitKey(DWORD dwProvType, LPCWSTR pwszProvider, DWORD dwUserKeySpec) { DWORD dwKeySpec=0; DWORD dwCSPCount=0; DWORD dwIndex=0; LPWSTR rgwszCSP[]={MS_DEF_PROV_W, MS_ENHANCED_PROV_W, MS_STRONG_PROV_W, MS_DEF_RSA_SCHANNEL_PROV_W, MS_DEF_DSS_PROV_W, MS_DEF_DSS_DH_PROV_W, MS_ENH_DSS_DH_PROV_W, MS_DEF_DH_SCHANNEL_PROV_W}; DWORD dwFlags=0; DWORD cbSize=0; PROV_ENUMALGS_EX paramData; DWORD dwMin=0; DWORD dwMax=0;
HCRYPTPROV hProv = NULL;
//if dwProvType is 0, we are using the base provider, which supports
//1024 bit in all key spec
if(0 == dwProvType) return TRUE;
if(pwszProvider) { dwCSPCount=sizeof(rgwszCSP)/sizeof(rgwszCSP[0]);
for(dwIndex=0; dwIndex < dwCSPCount; dwIndex++) { if(0 == _wcsicmp(pwszProvider, rgwszCSP[dwIndex])) break; }
if(dwIndex != dwCSPCount) return TRUE; }
dwKeySpec=dwUserKeySpec;
//xenroll uses AT_SIGNATURE as the default
if(0 == dwKeySpec) dwKeySpec=AT_SIGNATURE;
if(!CryptAcquireContextU(&hProv, NULL, pwszProvider, dwProvType, CRYPT_VERIFYCONTEXT)) return FALSE;
//get the max/min of key length for both signature and encryption
dwFlags=CRYPT_FIRST; cbSize=sizeof(paramData); memset(¶mData, 0, sizeof(PROV_ENUMALGS_EX));
while(CryptGetProvParam( hProv, PP_ENUMALGS_EX, (BYTE *) ¶mData, &cbSize, dwFlags)) { if(AT_SIGNATURE == dwKeySpec) { if (ALG_CLASS_SIGNATURE == GET_ALG_CLASS(paramData.aiAlgid)) { dwMax = paramData.dwMaxLen; dwMin = paramData.dwMinLen;
break; } } else { if(AT_KEYEXCHANGE == dwKeySpec) { if (ALG_CLASS_KEY_EXCHANGE == GET_ALG_CLASS(paramData.aiAlgid)) { dwMax = paramData.dwMaxLen; dwMin = paramData.dwMinLen;
break; } } }
dwFlags=0; cbSize=sizeof(paramData); memset(¶mData, 0, sizeof(PROV_ENUMALGS_EX)); }
if(hProv) CryptReleaseContext(hProv, 0);
if((1024 >= dwMin) && (1024 <= dwMax)) return TRUE;
return FALSE;
}
BOOL GetValidKeySizes (IN LPCWSTR pwszProvider, IN DWORD dwProvType, IN DWORD dwUserKeySpec, OUT DWORD * pdwMinLen, OUT DWORD * pdwMaxLen, OUT DWORD * pdwInc) { BOOL fDone = FALSE; BOOL fFoundAlgorithm = FALSE; BOOL fResult = FALSE; DWORD cbSize = 0; DWORD dwFlags = 0; DWORD dwParam = 0; HCRYPTPROV hProv = NULL; PROV_ENUMALGS_EX paramData;
if((NULL==pwszProvider) || (0 == dwProvType)) goto InvalidArgError;
if (!CryptAcquireContextU (&hProv, NULL, pwszProvider, dwProvType, CRYPT_VERIFYCONTEXT)) goto CryptAcquireContextUError;
dwFlags = CRYPT_FIRST; cbSize = sizeof(paramData); while((!fDone) && (!fFoundAlgorithm)) { memset(¶mData, 0, sizeof(PROV_ENUMALGS_EX)); // We're done searching if CryptGetProvParam fails.
fDone = !CryptGetProvParam (hProv, PP_ENUMALGS_EX, (BYTE *) ¶mData, &cbSize, dwFlags);
// We know we've found the algorithm we want if our key spec matches
// the algorithmic class of the algorithm.
fFoundAlgorithm = (ALG_CLASS_SIGNATURE == GET_ALG_CLASS(paramData.aiAlgid)) && (AT_SIGNATURE == dwUserKeySpec);
fFoundAlgorithm |= (ALG_CLASS_KEY_EXCHANGE == GET_ALG_CLASS(paramData.aiAlgid)) && (AT_KEYEXCHANGE == dwUserKeySpec);
// Don't want to keep enumerating the first element.
dwFlags &= ~CRYPT_FIRST; }
// Couldn't find an algorithm based on the keyspec
if (fDone) { goto ErrorReturn; }
// Ok, we've found the algorithm we're looking for, assign two of
// our out parameters.
*pdwMaxLen = paramData.dwMaxLen; *pdwMinLen = paramData.dwMinLen;
// Now, find the increment.
dwParam = (AT_SIGNATURE == dwUserKeySpec) ? PP_SIG_KEYSIZE_INC : PP_KEYX_KEYSIZE_INC; cbSize = sizeof(DWORD); if (!CryptGetProvParam (hProv, dwParam, (BYTE *)pdwInc, // Assigns final the out parameter
&cbSize, 0)) goto CryptGetProvParamError;
fResult = TRUE; ErrorReturn: if (NULL != hProv) { CryptReleaseContext(hProv, 0); } return fResult;
TRACE_ERROR(CryptAcquireContextUError); TRACE_ERROR(CryptGetProvParamError); SET_ERROR(InvalidArgError, E_INVALIDARG); }
HRESULT WINAPI CreateRequest(DWORD dwFlags, //IN Required
DWORD dwPurpose, //IN Required: Whether it is enrollment or renew
LPWSTR pwszCAName, //IN Required:
LPWSTR pwszCALocation, //IN Required:
CERT_BLOB *pCertBlob, //IN Required: The renewed certifcate
CERT_REQUEST_PVK_NEW *pRenewKey, //IN Required: The private key on the certificate
BOOL fNewKey, //IN Required: Set the TRUE if new private key is needed
CERT_REQUEST_PVK_NEW *pKeyNew, //IN Required: The private key information
LPWSTR pwszHashAlg, //IN Optional: The hash algorithm
LPWSTR pwszDesStore, //IN Optional: The destination store
DWORD dwStoreFlags, //IN Optional: The store flags
CERT_ENROLL_INFO *pRequestInfo, //IN Required: The information about the cert request
HANDLE *hRequest //OUT Required: A handle to the PKCS10 request created
) {
BSTR bstrCA = NULL; CRYPT_DATA_BLOB descriptionBlob; CRYPT_DATA_BLOB friendlyNameBlob; CRYPT_DATA_BLOB hashBlob; CRYPT_DATA_BLOB RequestBlob; CRYPT_KEY_PROV_INFO KeyProvInfo; DWORD dwIndex = 0; DWORD dwCAAndRootStoreFlags; HRESULT hr = E_FAIL; IEnroll4 *pIEnroll = NULL; LONG lRequestFlags = 0; LPWSTR pwszCA = NULL; PCCERT_CONTEXT pRenewCertContext = NULL; PCCERT_CONTEXT pArchivalCert = NULL; PCREATE_REQUEST_WIZARD_STATE pState = NULL; PFNPIEnroll4GetNoCOM pfnPIEnroll4GetNoCOM = NULL; BOOL fV2TemplateRequest = FALSE;
//input param checking
if(NULL == pKeyNew || NULL == pRequestInfo || NULL == hRequest) return E_INVALIDARG; // Check for versioning errors:
if(pKeyNew->dwSize != sizeof(CERT_REQUEST_PVK_NEW) || pRequestInfo->dwSize != sizeof(CERT_ENROLL_INFO)) return E_INVALIDARG;
// Init:
memset(&descriptionBlob, 0, sizeof(descriptionBlob)); memset(&friendlyNameBlob, 0, sizeof(friendlyNameBlob)); memset(&RequestBlob, 0, sizeof(RequestBlob)); memset(&hashBlob, 0, sizeof(hashBlob));
//////////////////////////////////////////////////////////////
//
// Acquire an IEnroll4 object.
//
//
// 1) load the library "xEnroll.dll".
//
if(NULL==g_hmodxEnroll) { if(NULL==(g_hmodxEnroll=LoadLibrary("xenroll.dll"))) goto Win32Err; } //
// 2) Get a pointer to the function that returns an IEnroll 4 object
// without using COM.
//
if(NULL==(pfnPIEnroll4GetNoCOM=(PFNPIEnroll4GetNoCOM)GetProcAddress(g_hmodxEnroll, "PIEnroll4GetNoCOM"))) goto Win32Err; //
// 3) Get the IEnroll4 object:
//
if(NULL==(pIEnroll=pfnPIEnroll4GetNoCOM())) goto GeneralErr;
//
//////////////////////////////////////////////////////////////
// Set the key size to the default, if it is not specified:
if(fNewKey) { //we set the default to 1024 is not specified by user
if(0 == (0xFFFF0000 & pKeyNew->dwGenKeyFlags)) { if(CanUse1024BitKey(pKeyNew->dwProvType, pKeyNew->pwszProvider, pKeyNew->dwKeySpec)) { pKeyNew->dwGenKeyFlags=pKeyNew->dwGenKeyFlags | (1024 << 16); } } }
if(dwStoreFlags) { //we either open CA and Root on the local machine or the current user
if(CERT_SYSTEM_STORE_CURRENT_USER != dwStoreFlags) dwCAAndRootStoreFlags = CERT_SYSTEM_STORE_LOCAL_MACHINE; else dwCAAndRootStoreFlags = dwStoreFlags; }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Set XENROLL properties.
// The property corresponding to "Property Name" is set to "Property Value", IF "Condition" evaluates to TRUE:
//
// Condition Property Name Property Value
// -----------------------------------------------------------------------------------------------------------------------------------
//
_SET_XENROLL_PROPERTY_IF(dwStoreFlags, CAStoreFlags, dwCAAndRootStoreFlags); _SET_XENROLL_PROPERTY_IF(pKeyNew->pwszKeyContainer, ContainerNameWStr, (LPWSTR)(pKeyNew->pwszKeyContainer)); _SET_XENROLL_PROPERTY_IF(TRUE, EnableSMIMECapabilities, pKeyNew->dwEnrollmentFlags & CT_FLAG_INCLUDE_SYMMETRIC_ALGORITHMS); _SET_XENROLL_PROPERTY_IF(pwszHashAlg, HashAlgorithmWStr, pwszHashAlg); _SET_XENROLL_PROPERTY_IF(TRUE, GenKeyFlags, pKeyNew->dwGenKeyFlags); _SET_XENROLL_PROPERTY_IF(pKeyNew->dwKeySpec, KeySpec, pKeyNew->dwKeySpec); _SET_XENROLL_PROPERTY_IF(dwStoreFlags, MyStoreFlags, dwStoreFlags); _SET_XENROLL_PROPERTY_IF(pwszDesStore, MyStoreNameWStr, pwszDesStore); _SET_XENROLL_PROPERTY_IF(pKeyNew->dwProviderFlags, ProviderFlags, pKeyNew->dwProviderFlags); _SET_XENROLL_PROPERTY_IF(pKeyNew->dwProvType, ProviderType, pKeyNew->dwProvType); _SET_XENROLL_PROPERTY_IF(dwStoreFlags, RootStoreFlags, dwCAAndRootStoreFlags); _SET_XENROLL_PROPERTY_IF(TRUE, UseExistingKeySet, !fNewKey); _SET_XENROLL_PROPERTY_IF(TRUE, WriteCertToUserDS, pRequestInfo->dwPostOption & CRYPTUI_WIZ_CERT_REQUEST_POST_ON_DS);
_SET_XENROLL_PROPERTY_IF(pKeyNew->dwProvType && pKeyNew->pwszProvider, ProviderNameWStr, (LPWSTR)(pKeyNew->pwszProvider)); _SET_XENROLL_PROPERTY_IF(CRYPTUI_WIZ_NO_INSTALL_ROOT & dwFlags, RootStoreNameWStr, L"CA"); _SET_XENROLL_PROPERTY_IF(TRUE, ReuseHardwareKeyIfUnableToGenNew, 0 == (dwFlags & CRYPTUI_WIZ_CERT_REQUEST_REQUIRE_NEW_KEY));
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
//
// Perform remaining XENROLL configuration:
//
// 1) Add the extensions to the certificate request
//
for(dwIndex=0; dwIndex < pRequestInfo->dwExtensions; dwIndex++) { if(NULL != pRequestInfo->prgExtensions[dwIndex]) { PCERT_EXTENSIONS prgExtensions = pRequestInfo->prgExtensions[dwIndex]; for (DWORD dwIndex2 = 0; dwIndex2 < prgExtensions->cExtension; dwIndex2++) { CERT_EXTENSION certExtension = prgExtensions->rgExtension[dwIndex2]; LPWSTR pwszName = NULL;
if(FALSE == fV2TemplateRequest) { if(0 == _stricmp(szOID_CERTIFICATE_TEMPLATE, certExtension.pszObjId)) fV2TemplateRequest = TRUE; }
if (S_OK != (hr = WizardSZToWSZ(certExtension.pszObjId, &pwszName))) goto ErrorReturn;
hr = pIEnroll->addExtensionToRequestWStr (certExtension.fCritical, pwszName, &(certExtension.Value));
// Make sure we always free pwszName.
if (NULL != pwszName) { WizardFree(pwszName); }
if (S_OK != hr) goto xEnrollErr; } } }
//
// 2) Set the key archival certificate, if requested by the cert template.
//
if (pKeyNew->dwPrivateKeyFlags & CT_FLAG_ALLOW_PRIVATE_KEY_ARCHIVAL) { if (NULL == pwszCAName || NULL == pwszCALocation) goto InvalidArgErr;
LPWSTR rgwszStrsToConcat[] = { pwszCALocation, L"\\", pwszCAName } ;
pwszCA = WizardAllocAndConcatStrsU(rgwszStrsToConcat, 3); if (NULL == pwszCA) goto MemoryErr;
bstrCA = SysAllocString(pwszCA); if (NULL == bstrCA) goto MemoryErr;
// Cert type specifies key archival.
if (S_OK != (hr = GetCAExchangeCertificate(bstrCA, &pArchivalCert))) goto xEnrollErr; if (S_OK != (hr = pIEnroll->SetPrivateKeyArchiveCertificate(pArchivalCert))) goto xEnrollErr; } //
// 3) If renewing, do the requisite extra work...
//
if(CRYPTUI_WIZ_CERT_RENEW & dwPurpose) { if(NULL == pCertBlob || NULL == pRenewKey) goto InvalidArgErr;
//create a certificate context
pRenewCertContext=CertCreateCertificateContext( X509_ASN_ENCODING, pCertBlob->pbData, pCertBlob->cbData); if(NULL == pRenewCertContext) goto CertCliErr;
//set the property for keyProvInfo
memset(&KeyProvInfo, 0, sizeof(CRYPT_KEY_PROV_INFO));
KeyProvInfo.dwProvType=pRenewKey->dwProvType; KeyProvInfo.pwszProvName=(LPWSTR)(pRenewKey->pwszProvider); KeyProvInfo.dwFlags=pRenewKey->dwProviderFlags; KeyProvInfo.pwszContainerName=(LPWSTR)(pRenewKey->pwszKeyContainer); KeyProvInfo.dwKeySpec=pRenewKey->dwKeySpec;
CertSetCertificateContextProperty( pRenewCertContext, CERT_KEY_PROV_INFO_PROP_ID, 0, &KeyProvInfo);
//set the RenewCertContext
if (0 == (dwFlags & CRYPTUI_WIZ_NO_ARCHIVE_RENEW_CERT)) { if (S_OK !=(hr=pIEnroll->put_RenewalCertificate(pRenewCertContext))) goto xEnrollErr; } else { // we add the signing certificate
if(S_OK != (hr = pIEnroll->SetSignerCertificate(pRenewCertContext))) goto xEnrollErr; } }
// Add certificate context properties to the request:
// 1) Add the friendly name property
if (NULL != pRequestInfo->pwszFriendlyName) { friendlyNameBlob.cbData = sizeof(WCHAR) * (wcslen(pRequestInfo->pwszFriendlyName) + 1); friendlyNameBlob.pbData = (LPBYTE)WizardAllocAndCopyWStr((LPWSTR)pRequestInfo->pwszFriendlyName); if (NULL == friendlyNameBlob.pbData) goto MemoryErr;
if (S_OK != (hr = pIEnroll-> addBlobPropertyToCertificateWStr (CERT_FRIENDLY_NAME_PROP_ID, 0, &friendlyNameBlob))) goto xEnrollErr; }
// 2) Add the description property
if (NULL != pRequestInfo->pwszDescription) { descriptionBlob.cbData = sizeof(WCHAR) * (wcslen(pRequestInfo->pwszDescription) + 1); descriptionBlob.pbData = (LPBYTE)WizardAllocAndCopyWStr((LPWSTR)pRequestInfo->pwszDescription); if (NULL == descriptionBlob.pbData) goto MemoryErr;
if (S_OK != (hr = pIEnroll-> addBlobPropertyToCertificateWStr (CERT_DESCRIPTION_PROP_ID, 0, &descriptionBlob))) goto xEnrollErr; } //////////////////////////////////////////////////////////////////////////////////
//
// At last, generate the request, and assign the out parameters:
//
//
// 1) Create the request. For V2 template, use CMC.
// For V1 template, use a PKCS7 for renewal, and PKCS10 for enrollment.
//
{ if(TRUE == fV2TemplateRequest) { lRequestFlags = XECR_CMC; } else { if (CRYPTUI_WIZ_CERT_RENEW & dwPurpose) { // We're renewing: use PKCS7.
lRequestFlags = XECR_PKCS7; } else { // Enrolling with no PVK archival support: use PKCS10.
lRequestFlags = XECR_PKCS10_V2_0; } } if (FAILED(hr=pIEnroll->createRequestWStr (lRequestFlags, pRequestInfo->pwszCertDNName, //L"CN=Test Certificate",
pRequestInfo->pwszUsageOID, //pwszUsage
&RequestBlob))) goto xEnrollErr; } //
// 2) Get the HASH of the request so we can supply it to xenroll when we submit:
//
{ pState = (PCREATE_REQUEST_WIZARD_STATE)WizardAlloc(sizeof(CREATE_REQUEST_WIZARD_STATE)); if (pState == NULL) goto MemoryErr;
if (S_OK != (hr = pIEnroll->get_ThumbPrintWStr(&hashBlob))) goto xEnrollErr; hashBlob.pbData = (LPBYTE)WizardAlloc(hashBlob.cbData); if (NULL == hashBlob.pbData) goto MemoryErr;
if (S_OK != (hr = pIEnroll->get_ThumbPrintWStr(&hashBlob))) goto xEnrollErr;
//
// 3) Create a blob to assign our OUT parameter to.
// This blob preserves state from the call of CreateRequest() to the call
// of SubmitRequest()
//
pState->fMustFreeRequestBlob = TRUE; pState->RequestBlob = RequestBlob; pState->HashBlob = hashBlob;
// Persist certificate store information:
pState->dwMyStoreFlags = dwStoreFlags; pState->dwRootStoreFlags = dwCAAndRootStoreFlags;
pState->pwszMyStoreName = NULL == pwszDesStore ? NULL : WizardAllocAndCopyWStr(pwszDesStore); _JumpCondition(NULL != pwszDesStore && NULL == pState->pwszMyStoreName, MemoryErr);
pState->pwszRootStoreName = CRYPTUI_WIZ_NO_INSTALL_ROOT & dwFlags ? L"CA" : NULL;
// Persist the request type:
pState->lRequestFlags = lRequestFlags;
// Persist status information: did we need to reuse the private key?
hr = pIEnroll->get_UseExistingKeySet(&pState->fReusedPrivateKey); if (FAILED(hr)) goto xEnrollErr;
pState->fNewKey = fNewKey;
//
// 4) Assign cast the request to a handle and return it:
//
*hRequest = (HANDLE)pState; } //
//////////////////////////////////////////////////////////////////////////////////
// We're done!
hr = S_OK; CommonReturn: if (NULL != bstrCA) { SysFreeString(bstrCA); } if (NULL != pArchivalCert) { CertFreeCertificateContext(pArchivalCert); } if (NULL != pIEnroll) { pIEnroll->Release(); } if (NULL != pRenewCertContext) { CertFreeCertificateContext(pRenewCertContext); } if (NULL != pwszCA) { WizardFree(pwszCA); } if (NULL != descriptionBlob.pbData) { WizardFree(descriptionBlob.pbData); } if (NULL != friendlyNameBlob.pbData) { WizardFree(friendlyNameBlob.pbData); }
//return values
return hr;
ErrorReturn: if(NULL != RequestBlob.pbData) { // NOTE: pIEnroll can not be NULL because it is used to allocate RequestBlob
pIEnroll->freeRequestInfoBlob(RequestBlob); // This memory is from xenroll: must use LocalFree().
LocalFree(RequestBlob.pbData); }
if (NULL != pState) { WizardFree(pState); }
if (NULL != hashBlob.pbData) { WizardFree(hashBlob.pbData); } goto CommonReturn;
SET_HRESULT(CertCliErr, CodeToHR(GetLastError())); SET_HRESULT(GeneralErr, E_FAIL); SET_HRESULT(InvalidArgErr, E_INVALIDARG); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); SET_HRESULT(xEnrollErr, hr); SET_HRESULT(Win32Err, CodeToHR(GetLastError())); }
BSTR GetClientAttribs() { HRESULT hr; DOMAIN_CONTROLLER_INFO *pDomainInfo = NULL; BSTR strAttr = NULL; WCHAR const *pwszDC = NULL; DWORD cwc; DWORD cwcDNS;
hr = DsGetDcName( NULL, NULL, NULL, NULL, DS_RETURN_DNS_NAME, &pDomainInfo); if (S_OK == hr) { pwszDC = pDomainInfo->DomainControllerName; while (L'\\' == *pwszDC) { pwszDC++; } }
cwcDNS = 0; if (!GetComputerNameExW(ComputerNameDnsFullyQualified, NULL, &cwcDNS)) { hr = GetLastError(); if ((HRESULT) ERROR_MORE_DATA != hr) { cwcDNS = 0; } } else { cwcDNS++; }
cwc = 0; if (NULL != pwszDC) { cwc += wcslen(wszPROPCLIENTDCDNS) + 1 + wcslen(pwszDC); } if (0 != cwcDNS) { if (NULL != pwszDC) { cwc++; }
// cwcDNS includes the trailing NULL WCHAR, cwc should not.
cwc += wcslen(wszPROPREQUESTMACHINEDNS) + 1 + cwcDNS - 1; } if (0 == cwc) { goto error; } strAttr = SysAllocStringLen(NULL, cwc); if (NULL == strAttr) { hr = E_OUTOFMEMORY; goto error; } strAttr[0] = L'\0'; if (NULL != pwszDC) { wcscat(strAttr, wszPROPCLIENTDCDNS L":"); wcscat(strAttr, pwszDC); } if (0 != cwcDNS) { WCHAR *pwszTruncate = &strAttr[wcslen(strAttr)]; WCHAR *pwsz; if (NULL != pwszDC) { wcscat(strAttr, L"\n"); } wcscat(strAttr, wszPROPREQUESTMACHINEDNS L":"); pwsz = &strAttr[wcslen(strAttr)]; if (!GetComputerNameExW(ComputerNameDnsFullyQualified, pwsz, &cwcDNS)) { hr = GetLastError(); } else { pwszTruncate = &pwsz[cwcDNS]; } assert(pwszTruncate <= &strAttr[cwc]); *pwszTruncate = L'\0'; } assert(wcslen(strAttr) == cwc); assert(SysStringLen(strAttr) == cwc); hr = S_OK;
error: if (NULL != pDomainInfo) { NetApiBufferFree(pDomainInfo); } return(strAttr); }
HRESULT WINAPI SubmitRequest(IN HANDLE hRequest, IN BOOL fKeyService, //IN Required: Whether the function is called remotely
IN DWORD /*dwPurpose*/, //IN deprecated: we don't use purpose during submit anymore
IN BOOL /*fConfirmation*/, //IN deprecated: we no longer have a confirmation dialog
IN HWND /*hwndParent*/, //IN deprecated: we no longer have a confirmation dialog
IN LPWSTR /*pwszConfirmationTitle*/, //IN deprecated: we no longer have a confirmation dialog
IN UINT /*idsConfirmTitle*/, //IN deprecated: we no longer have a confirmation dialog
IN LPWSTR pwszCALocation, //IN Required: The ca machine name
IN LPWSTR pwszCAName, //IN Required: The ca name
IN LPWSTR pwszCADisplayName, // IN Optional: The display name of the CA.
OUT CERT_BLOB *pPKCS7Blob, //OUT Optional: The PKCS7 from the CA
OUT CERT_BLOB *pHashBlob, //OUT Optioanl: The SHA1 hash of the enrolled/renewed certificate
OUT DWORD *pdwDisposition, //OUT Optional: The status of the enrollment/renewal
OUT PCCERT_CONTEXT *ppCertContext //OUT Optional: The enrolled certificate
) { BOOL fNewKey; BSTR bstrAttribs = NULL; // Always NULL.
BSTR bstrCA = NULL; // "CA Location\CA Name"
BSTR bstrCMC = NULL; // BSTR representation of the CMC certificate.
BSTR bstrPKCS7 = NULL; // BSTR representation of the PKCS7 certificate.
BSTR bstrReq = NULL; // BSTR representation of the PKCS10 request.
CRYPT_DATA_BLOB CMCBlob; // CMC encoded issued certificate.
CRYPT_DATA_BLOB HashBlob; CRYPT_DATA_BLOB PKCS7Blob; // PKCS7 encoded issued certificate.
CRYPT_DATA_BLOB PropertyBlob; // Temporary variable.
CRYPT_DATA_BLOB RequestBlob; DWORD dwRequestID; // The request ID of the submitted request.
DWORD dwDisposition; // The disposition of the submitted request.
DWORD dwMyStoreFlags = 0; DWORD dwRootStoreFlags = 0;
// BUGBUG: need to use global enrollment factory.
EnrollmentCOMObjectFactory *pEnrollFactory = NULL; HRESULT hr = E_FAIL; // Return code.
ICertRequest2 *pICertRequest = NULL; // Used to submit request to CA.
IEnroll4 *pIEnroll = NULL; // Used to install issued certificate.
LONG lRequestFlags = 0; LPWSTR pwszCA = NULL; // "CA Location\CA Name"
LPWSTR pwszMyStoreName = NULL; LPWSTR pwszRootStoreName = NULL; PCCERT_CONTEXT pCertContext = NULL; // The (hopefully) issued certificate.
PCREATE_REQUEST_WIZARD_STATE pState = NULL; PFNPIEnroll4GetNoCOM pfnPIEnroll4GetNoCOM = NULL; // Function that acquires an IEnroll4 object without using COM.
VARIANT varCMC;
LocalScope(SubmitRequestHelper): DWORD ICEnrollDispositionToCryptUIStatus(DWORD dwDisposition) { switch (dwDisposition) { case CR_DISP_INCOMPLETE: return CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR; case CR_DISP_ERROR: return CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR; case CR_DISP_DENIED: return CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_DENIED; case CR_DISP_ISSUED_OUT_OF_BAND: return CRYPTUI_WIZ_CERT_REQUEST_STATUS_ISSUED_SEPARATELY; case CR_DISP_UNDER_SUBMISSION: return CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNDER_SUBMISSION; case CR_DISP_ISSUED: return CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED; default: // Something's wrong.
return CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR; } } EndLocalScope;
// Input Validation:
if (NULL == pwszCALocation || NULL == pwszCAName || NULL == hRequest) return E_INVALIDARG;
// Initialization:
if (NULL != pPKCS7Blob) memset(pPKCS7Blob, 0, sizeof(CERT_BLOB));
if (NULL != pHashBlob) memset(pHashBlob, 0, sizeof(CERT_BLOB));
if (NULL != ppCertContext) *ppCertContext=NULL;
memset(&CMCBlob, 0, sizeof(CRYPT_DATA_BLOB)); memset(&PKCS7Blob, 0, sizeof(CRYPT_DATA_BLOB)); memset(&PropertyBlob, 0, sizeof(CRYPT_DATA_BLOB)); VariantInit(&varCMC);
dwDisposition = CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNKNOWN;
// We're using a COM component in this method. It's absolutely necessary that we
// uninitialize COM before we return, because we're running in an RPC thread,
// and failing to uninitialize COM will cause us to step on RPC's toes.
//
// See BUG 404778.
pEnrollFactory = new EnrollmentCOMObjectFactory; if (NULL == pEnrollFactory) goto MemoryErr; __try { //////////////////////////////////////////////////////////////
//
// Extract the data we need from the IN handle.
//
pState = (PCREATE_REQUEST_WIZARD_STATE)hRequest; RequestBlob = pState->RequestBlob; HashBlob = pState->HashBlob; dwMyStoreFlags = pState->dwMyStoreFlags; dwRootStoreFlags = pState->dwRootStoreFlags; pwszMyStoreName = pState->pwszMyStoreName; pwszRootStoreName = pState->pwszRootStoreName; fNewKey = pState->fNewKey;
lRequestFlags = CR_IN_BINARY; switch (pState->lRequestFlags) { case XECR_PKCS10_V2_0: lRequestFlags |= CR_IN_PKCS10; break; case XECR_PKCS7: lRequestFlags |= CR_IN_PKCS7; break; case XECR_CMC: lRequestFlags |= CR_IN_CMC; break; default: goto InvalidArgErr; }
//////////////////////////////////////////////////////////////
//
// Acquire an IEnroll4 object.
//
//
// 1) load the library "xEnroll.dll".
//
if(NULL==g_hmodxEnroll) { if(NULL==(g_hmodxEnroll=LoadLibrary("xenroll.dll"))) goto Win32Err; } //
// 2) Get a pointer to the function that returns an IEnroll 4 object
// without using COM.
//
if(NULL==(pfnPIEnroll4GetNoCOM=(PFNPIEnroll4GetNoCOM)GetProcAddress(g_hmodxEnroll, "PIEnroll4GetNoCOM"))) goto Win32Err; //
// 3) Get the IEnroll4 object:
//
if(NULL==(pIEnroll=pfnPIEnroll4GetNoCOM())) goto GeneralErr;
//
// 4) Set the pending request to use:
//
if (S_OK != (hr = pIEnroll->put_ThumbPrintWStr(HashBlob))) goto xEnrollErr; // 5) Restore the old certificate store information:
_SET_XENROLL_PROPERTY_IF(dwMyStoreFlags, MyStoreFlags, dwMyStoreFlags); _SET_XENROLL_PROPERTY_IF(pwszMyStoreName, MyStoreNameWStr, pwszMyStoreName); _SET_XENROLL_PROPERTY_IF(dwRootStoreFlags, RootStoreFlags, dwRootStoreFlags); _SET_XENROLL_PROPERTY_IF(pwszRootStoreName, RootStoreNameWStr, pwszRootStoreName); _SET_XENROLL_PROPERTY_IF(TRUE, UseExistingKeySet, !fNewKey);
//
//////////////////////////////////////////////////////////////
// Convert request blob to a BSTR:
bstrReq = SysAllocStringByteLen((LPCSTR)RequestBlob.pbData, RequestBlob.cbData); if (NULL == bstrReq) goto MemoryErr;
bstrAttribs = GetClientAttribs();
// Acquire and use an ICertRequest2 object to submit the request to the CA:
if (pICertRequest == NULL) { if (S_OK != (hr = pEnrollFactory->getICertRequest2(&pICertRequest))) goto ErrorReturn; }
// bstrCA <-- pwszCALocation\pwszCAName
{ LPWSTR rgwszStrsToConcat[] = { pwszCALocation, L"\\", pwszCAName } ; pwszCA = WizardAllocAndConcatStrsU(rgwszStrsToConcat, 3); if (NULL == pwszCA) goto MemoryErr; } bstrCA = SysAllocString(pwszCA); if (NULL == bstrCA) goto MemoryErr;
hr = pICertRequest->Submit (lRequestFlags, bstrReq, bstrAttribs, bstrCA, (long *)&dwDisposition);
dwDisposition = local.ICEnrollDispositionToCryptUIStatus(dwDisposition); _JumpCondition(S_OK != hr, ErrorReturn);
// Deal with the possible status codes we could've encountered:
switch (dwDisposition) { case CRYPTUI_WIZ_CERT_REQUEST_STATUS_CONNECTION_FAILED: case CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR: case CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_DENIED: case CRYPTUI_WIZ_CERT_REQUEST_STATUS_ISSUED_SEPARATELY: if (S_OK == hr) { pICertRequest->GetLastStatus((LONG *)&hr); if(!FAILED(hr)) hr=E_FAIL; } goto ErrorReturn;
case CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNDER_SUBMISSION: // The certificate request has pended. Set the pending request info.
if (S_OK != (hr = pICertRequest->GetRequestId((long *)&dwRequestID))) goto ErrorReturn;
if (S_OK != (hr = pIEnroll->setPendingRequestInfoWStr (dwRequestID, pwszCALocation, pwszCAName, NULL))) goto setPendingRequestInfoWStrError;
// The request has pended, we don't need to delete it from the request store...
pState->fMustFreeRequestBlob = FALSE;
goto CommonReturn; case CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED: // 4) Success! Continue processing...
break; default: // 5) Invalid error code:
goto UnexpectedErr; }
if (S_OK != (hr = pICertRequest->GetFullResponseProperty(FR_PROP_FULLRESPONSE, 0, PROPTYPE_BINARY, CR_OUT_BINARY, &varCMC))) goto ErrorReturn; // Check to make sure we've gotten a BSTR back:
if (VT_BSTR != varCMC.vt) { dwDisposition = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT); goto ErrorReturn; } bstrCMC = varCMC.bstrVal; // Marshal the cert into a CRYPT_DATA_BLOB:
CMCBlob.pbData = (LPBYTE)bstrCMC; CMCBlob.cbData = SysStringByteLen(bstrCMC); if (S_OK != (hr = pIEnroll->getCertContextFromResponseBlob(&CMCBlob, &pCertContext))) { dwDisposition = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; goto ErrorReturn; } // Install the certificate, and delete the request from the request store.
if(S_OK !=(hr=pIEnroll->acceptResponseBlob(&CMCBlob))) { dwDisposition = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; goto xEnrollErr; } // acceptPKCS7Blob cleans up the request store for us ... we don't need to
// do this explicitly anyone.
pState->fMustFreeRequestBlob = FALSE;
////////////////////////////////////////////////////////////////////////////////
//
// Assign the OUT parameters:
//
//
// 1) Assign the PKCS7 Blob to the OUT PKCS7 blob:
//
if(NULL != pPKCS7Blob) { // Get a PKCS7 Blob to return to the client:
if (S_OK != (hr = pICertRequest->GetCertificate(CR_OUT_BINARY | CR_OUT_CHAIN, &bstrPKCS7))) goto ErrorReturn; // Marshal the cert into a CRYPT_DATA_BLOB:
PKCS7Blob.pbData = (LPBYTE)bstrPKCS7; PKCS7Blob.cbData = SysStringByteLen(bstrPKCS7); pPKCS7Blob->pbData=(BYTE *)WizardAlloc(PKCS7Blob.cbData); if(NULL==(pPKCS7Blob->pbData)) { dwDisposition = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; goto MemoryErr; } memcpy(pPKCS7Blob->pbData, PKCS7Blob.pbData,PKCS7Blob.cbData); pPKCS7Blob->cbData=PKCS7Blob.cbData; } //
// 2) Assign the SHA1 hash blob of the cert to the OUT hashblob.
//
if(NULL != pHashBlob) { if(!CertAllocAndGetCertificateContextProperty( pCertContext, CERT_SHA1_HASH_PROP_ID, (LPVOID *)&(pHashBlob->pbData), &(pHashBlob->cbData))) { dwDisposition = CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; goto CertCliErr; } } //
// 3) Return the certificate context on the local case
//
if((NULL != ppCertContext) && !fKeyService) { *ppCertContext = CertDuplicateCertificateContext(pCertContext); } //
////////////////////////////////////////////////////////////////////////////////
} __except (EXCEPTION_EXECUTE_HANDLER) { hr = GetExceptionCode(); goto ErrorReturn; }
dwDisposition = CRYPTUI_WIZ_CERT_REQUEST_STATUS_SUCCEEDED; hr=S_OK;
CommonReturn: if (NULL != bstrCA) { SysFreeString(bstrCA); } if (NULL != bstrAttribs) { SysFreeString(bstrAttribs); } if (NULL != bstrReq) { SysFreeString(bstrReq); } if (NULL != pICertRequest) { pICertRequest->Release(); } if (NULL != bstrCMC) { SysFreeString(bstrCMC); } if (NULL != bstrPKCS7) { SysFreeString(bstrPKCS7); } if (NULL != pEnrollFactory) { delete pEnrollFactory; } if (NULL != pIEnroll) { pIEnroll->Release(); } if (NULL != pwszCA) { WizardFree(pwszCA); } if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); }
// PKCS7Blob.pbData is aliased to bstrCertificate. Just NULL it out:
PKCS7Blob.pbData = NULL;
// Always return a status code:
if (NULL != pdwDisposition) { *pdwDisposition = dwDisposition; }
return hr;
ErrorReturn: //free the output parameter
if (NULL != pPKCS7Blob && NULL != pPKCS7Blob->pbData) { WizardFree(pPKCS7Blob->pbData); memset(pPKCS7Blob, 0, sizeof(CERT_BLOB)); } //free the output parameter
if (NULL != pHashBlob && NULL != pHashBlob->pbData) { WizardFree(pHashBlob->pbData); memset(pHashBlob, 0, sizeof(CERT_BLOB)); }
if (NULL != ppCertContext && NULL != *ppCertContext) { CertFreeCertificateContext(*ppCertContext); } goto CommonReturn;
SET_HRESULT(CertCliErr, CodeToHR(GetLastError())); SET_HRESULT(GeneralErr, E_FAIL); SET_HRESULT(InvalidArgErr, E_INVALIDARG); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); SET_HRESULT(setPendingRequestInfoWStrError, hr); SET_HRESULT(UnexpectedErr, E_UNEXPECTED); SET_HRESULT(xEnrollErr, hr); SET_HRESULT(Win32Err, CodeToHR(GetLastError())); }
BOOL WINAPI QueryRequest(IN HANDLE hRequest, OUT CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO *pQueryInfo) { BOOL fResult; CREATE_REQUEST_WIZARD_STATE *pState; CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO QueryInfo;
memset(&QueryInfo, 0, sizeof(QueryInfo));
pState = (CREATE_REQUEST_WIZARD_STATE *)hRequest; QueryInfo.dwSize = sizeof(QueryInfo); QueryInfo.dwStatus = (pState->fReusedPrivateKey) ? CRYPTUI_WIZ_QUERY_CERT_REQUEST_STATUS_CREATE_REUSED_PRIVATE_KEY : 0;
*pQueryInfo = QueryInfo; fResult = TRUE; // CommonReturn:
return fResult; }
void WINAPI FreeRequest(IN HANDLE hRequest) { IEnroll4 *pIEnroll = NULL; PCREATE_REQUEST_WIZARD_STATE pState = NULL; PFNPIEnroll4GetNoCOM pfnPIEnroll4GetNoCOM = NULL;
if (NULL == hRequest) return; // Nothing to free!
pState = (PCREATE_REQUEST_WIZARD_STATE)hRequest;
// Make our best effort to get an IEnroll4 pointer:
if (NULL == g_hmodxEnroll) { g_hmodxEnroll = LoadLibrary("xenroll.dll"); } // We couldn't load xenroll -- not much we can do about it. In this case,
// it's likely we ever allocated memory with it anyway, however, so we're
// probably not leaking.
_JumpCondition(NULL == g_hmodxEnroll, xEnrollDone);
pfnPIEnroll4GetNoCOM = (PFNPIEnroll4GetNoCOM)GetProcAddress(g_hmodxEnroll, "PIEnroll4GetNoCOM"); _JumpCondition(NULL == pfnPIEnroll4GetNoCOM, xEnrollDone);
pIEnroll = pfnPIEnroll4GetNoCOM(); _JumpCondition(NULL == pIEnroll, xEnrollDone);
// Free the request created by xenroll.
// NOTE: freeRequestInfoBlob does not actually free the memory associated with the request.
// Rather, it deletes the request from the request store, leaving the caller responsible
// for the memory free.
if (pState->fMustFreeRequestBlob) { if (NULL != pState->RequestBlob.pbData) { if (NULL != pIEnroll) { pIEnroll->put_MyStoreFlags(pState->dwMyStoreFlags); if (NULL != pState->HashBlob.pbData) { pIEnroll->put_ThumbPrintWStr(pState->HashBlob); } pIEnroll->freeRequestInfoBlob(pState->RequestBlob); } LocalFree(pState->RequestBlob.pbData); } }
xEnrollDone: // We've finished attempting to free data created by xenroll. Now
// free data allocated in CreateRequest():
if (NULL != pState->HashBlob.pbData) { WizardFree(pState->HashBlob.pbData); } WizardFree(pState);
// We're done with the IEnroll4 pointer:
if (NULL != pIEnroll) { pIEnroll->Release(); } }
HRESULT WINAPI LocalEnrollNoDS( DWORD dwFlags, //IN Required
LPCWSTR /*pRequestString*/, // Reserved: must be NULL.
void *pReserved, //IN Optional
BOOL fKeyService, //IN Required: Whether the function is called remotely
DWORD dwPurpose, //IN Required: Whether it is enrollment or renew
BOOL fConfirmation, //IN Required: Set the TRUE if confirmation dialogue is needed
HWND hwndParent, //IN Optional: The parent window
LPWSTR pwszConfirmationTitle, //IN Optional: The title for confirmation dialogue
UINT idsConfirmTitle, //IN Optional: The resource ID for the title of the confirmation dialogue
LPWSTR pwszCALocation, //IN Required: The ca machine name
LPWSTR pwszCAName, //IN Required: The ca name
CERT_BLOB *pCertBlob, //IN Required: The renewed certifcate
CERT_REQUEST_PVK_NEW *pRenewKey, //IN Required: The private key on the certificate
BOOL fNewKey, //IN Required: Set the TRUE if new private key is needed
CERT_REQUEST_PVK_NEW *pKeyNew, //IN Required: The private key information
LPWSTR pwszHashAlg, //IN Optional: The hash algorithm
LPWSTR pwszDesStore, //IN Optional: The destination store
DWORD dwStoreFlags, //IN Optional: The store flags
CERT_ENROLL_INFO *pRequestInfo, //IN Required: The information about the cert request
CERT_BLOB *pPKCS7Blob, //OUT Optional: The PKCS7 from the CA
CERT_BLOB *pHashBlob, //OUT Optioanl: The SHA1 hash of the enrolled/renewed certificate
DWORD *pdwStatus, //OUT Optional: The status of the enrollment/renewal
HANDLE *pResult //IN OUT Optional: The enrolled certificate
)
{ // When no flags are specified, we still create, submit, and free.
BOOL fCreateRequest = 0 == (dwFlags & (CRYPTUI_WIZ_NODS_MASK & ~CRYPTUI_WIZ_CREATE_ONLY)); BOOL fSubmitRequest = 0 == (dwFlags & (CRYPTUI_WIZ_NODS_MASK & ~CRYPTUI_WIZ_SUBMIT_ONLY)); BOOL fFreeRequest = 0 == (dwFlags & (CRYPTUI_WIZ_NODS_MASK & ~CRYPTUI_WIZ_FREE_ONLY));
// Query the request only when specifically queried.
BOOL fQueryRequest = 0 != (dwFlags & CRYPTUI_WIZ_QUERY_ONLY); HANDLE hRequest = NULL; HRESULT hr = E_FAIL;
if (fQueryRequest) { // Querying the request takes precedence over other operations.
if (!QueryRequest(*pResult, (CRYPTUI_WIZ_QUERY_CERT_REQUEST_INFO *)pReserved)) goto QueryRequestErr;
return S_OK; }
if (NULL != pdwStatus) *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR;
if (FALSE == (fCreateRequest || fSubmitRequest || fFreeRequest)) return E_INVALIDARG; if (TRUE == fCreateRequest) { if (S_OK != (hr = CreateRequest(dwFlags, dwPurpose, pwszCAName, pwszCALocation, pCertBlob, pRenewKey, fNewKey, pKeyNew, pwszHashAlg, pwszDesStore, dwStoreFlags, pRequestInfo, &hRequest))) goto ErrorReturn;
_JumpCondition(NULL == hRequest, UnexpectedErr);
// Successfully created the request:
if (NULL != pdwStatus) { *pdwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_CREATED; } if (NULL != pResult) { *pResult = hRequest; } } else { // The created request is passed in through "pResult".
hRequest = *pResult; }
if (TRUE == fSubmitRequest) { if (S_OK != (hr = SubmitRequest (hRequest, fKeyService, dwPurpose, fConfirmation, hwndParent, pwszConfirmationTitle, idsConfirmTitle, pwszCALocation, pwszCAName, NULL, // pwszCADisplayName,
pPKCS7Blob, pHashBlob, pdwStatus, (PCCERT_CONTEXT *)pResult))) { // Assign the created request to the OUT parameter on error.
if (NULL != pResult) { *pResult = hRequest; } goto ErrorReturn; } }
if (TRUE == fFreeRequest) { FreeRequest(hRequest); hr = S_OK; }
CommonReturn: return hr;
ErrorReturn: goto CommonReturn;
SET_HRESULT(QueryRequestErr, GetLastError()); SET_HRESULT(UnexpectedErr, E_UNEXPECTED); }
HRESULT WINAPI LocalEnroll( DWORD dwFlags, //IN Required
LPCWSTR pRequestString, // Reserved: must be NULL.
void *pReserved, //IN Optional
BOOL fKeyService, //IN Required: Whether the function is called remotely
DWORD dwPurpose, //IN Required: Whether it is enrollment or renew
BOOL fConfirmation, //IN Required: Set the TRUE if confirmation dialogue is needed
HWND hwndParent, //IN Optional: The parent window
LPWSTR pwszConfirmationTitle, //IN Optional: The title for confirmation dialogue
UINT idsConfirmTitle, //IN Optional: The resource ID for the title of the confirmation dialogue
LPWSTR pwszCALocation, //IN Required: The ca machine name
LPWSTR pwszCAName, //IN Required: The ca name
CERT_BLOB *pCertBlob, //IN Required: The renewed certifcate
CERT_REQUEST_PVK_NEW *pRenewKey, //IN Required: The private key on the certificate
BOOL fNewKey, //IN Required: Set the TRUE if new private key is needed
CERT_REQUEST_PVK_NEW *pKeyNew, //IN Required: The private key information
LPWSTR pwszHashAlg, //IN Optional: The hash algorithm
LPWSTR pwszDesStore, //IN Optional: The destination store
DWORD dwStoreFlags, //IN Optional: The store flags
CERT_ENROLL_INFO *pRequestInfo, //IN Required: The information about the cert request
CERT_BLOB *pPKCS7Blob, //OUT Optional: The PKCS7 from the CA
CERT_BLOB *pHashBlob, //OUT Optioanl: The SHA1 hash of the enrolled/renewed certificate
DWORD *pdwStatus, //OUT Optional: The status of the enrollment/renewal
PCERT_CONTEXT *ppCertContext //OUT Optional: The enrolled certificate
) { return LocalEnrollNoDS ( dwFlags, //IN Required
pRequestString, // Reserved: must be NULL.
pReserved, //IN Optional
fKeyService, //IN Required: Whether the function is called remotely
dwPurpose, //IN Required: Whether it is enrollment or renew
fConfirmation, //IN Required: Set the TRUE if confirmation dialogue is needed
hwndParent, //IN Optional: The parent window
pwszConfirmationTitle, //IN Optional: The title for confirmation dialogue
idsConfirmTitle, //IN Optional: The resource ID for the title of the confirmation dialogue
pwszCALocation, //IN Required: The ca machine name
pwszCAName, //IN Required: The ca name
pCertBlob, //IN Required: The renewed certifcate
pRenewKey, //IN Required: The private key on the certificate
fNewKey, //IN Required: Set the TRUE if new private key is needed
pKeyNew, //IN Required: The private key information
pwszHashAlg, //IN Optional: The hash algorithm
pwszDesStore, //IN Optional: The destination store
dwStoreFlags, //IN Optional: The store flags
pRequestInfo, //IN Required: The information about the cert request
pPKCS7Blob, //OUT Optional: The PKCS7 from the CA
pHashBlob, //OUT Optioanl: The SHA1 hash of the enrolled/renewed certificate
pdwStatus, //OUT Optional: The status of the enrollment/renewal
(HANDLE *)ppCertContext); //OUT Optional: The enrolled certificate
}
//note pCertRenewPvk internal pointers has to be freed by callers
HRESULT MarshallRequestParameters(IN DWORD dwCSPIndex, IN CERT_WIZARD_INFO *pCertWizardInfo, IN OUT CERT_BLOB *pCertBlob, IN OUT CERT_REQUEST_PVK_NEW *pCertRequestPvkNew, IN OUT CERT_REQUEST_PVK_NEW *pCertRenewPvk, IN OUT LPWSTR *ppwszHashAlg, IN OUT CERT_ENROLL_INFO *pRequestInfo) { BOOL fCopyPropertiesFromRequestInfo = FALSE; BOOL fRevertWizardProvider = FALSE; BOOL fSetUpRenewPvk = FALSE; CertRequester *pCertRequester = NULL; CertRequesterContext *pCertRequesterContext = NULL; CRYPT_KEY_PROV_INFO *pKeyProvInfo = NULL; CRYPTUI_WIZ_CERT_CA *pCertCA = NULL; DWORD dwExtensions = 0; DWORD dwIndex = 0; DWORD dwGenKeyFlags = 0; DWORD dwSize = 0; HRESULT hr = E_FAIL; LPWSTR pwszOID = NULL; LPWSTR pwszUsageOID = NULL; PCERT_EXTENSIONS *pExtensions = NULL; UINT idsText = 0; DWORD dwMinKey = 0; DWORD dwMaxKey = 0; DWORD dwInc = 0; DWORD dwTempGenKeyFlags = 0;
// Input validation:
_JumpConditionWithExpr (NULL == pCertWizardInfo || NULL == pCertWizardInfo->hRequester || NULL == pCertBlob || NULL == pCertRequestPvkNew || NULL == pCertRenewPvk || NULL == ppwszHashAlg || NULL == pRequestInfo, InvalidArgError, idsText = IDS_REQUEST_FAIL);
// Initialization:
memset(pCertBlob, 0, sizeof(*pCertBlob)); memset(pCertRequestPvkNew, 0, sizeof(*pCertRequestPvkNew)); memset(pCertRenewPvk, 0, sizeof(*pCertRenewPvk)); memset(ppwszHashAlg, 0, sizeof(*ppwszHashAlg)); memset(pRequestInfo, 0, sizeof(*pRequestInfo));
pCertRequester = (CertRequester *)pCertWizardInfo->hRequester; pCertRequesterContext = pCertRequester->GetContext(); _JumpCondition(NULL == pCertRequesterContext, InvalidArgError);
//set up the hash algorithm. Convert to the wchar version
if(pCertWizardInfo->pszHashAlg) (*ppwszHashAlg) = MkWStr((LPSTR)(pCertWizardInfo->pszHashAlg));
// Build a comma seperated OID usage for enrollment only.
// The CA index must not exceed the number of CAs:
_JumpCondition(pCertWizardInfo->dwCAIndex >= pCertWizardInfo->pCertCAInfo->dwCA, UnexpectedError);
pCertCA=&(pCertWizardInfo->pCertCAInfo->rgCA[pCertWizardInfo->dwCAIndex]);
//decide if we need to build the list
if(pCertCA->dwOIDInfo) { pwszUsageOID=(LPWSTR)WizardAlloc(sizeof(WCHAR)); _JumpCondition(NULL == pwszUsageOID, MemoryError); *pwszUsageOID=L'\0'; //we are guaranteed that at least one OID should be selected
for(dwIndex=0; dwIndex<pCertCA->dwOIDInfo; dwIndex++) { if(TRUE==(pCertCA->rgOIDInfo)[dwIndex].fSelected) { if(wcslen(pwszUsageOID)!=0) wcscat(pwszUsageOID, L","); pwszOID=MkWStr((pCertCA->rgOIDInfo)[dwIndex].pszOID); _JumpCondition(NULL == pwszOID, MemoryError);
pwszUsageOID=(LPWSTR)WizardRealloc(pwszUsageOID, sizeof(WCHAR)*(wcslen(pwszUsageOID)+wcslen(pwszOID)+wcslen(L",")+1));
_JumpCondition(NULL==pwszUsageOID, MemoryError);
wcscat(pwszUsageOID,pwszOID);
FreeWStr(pwszOID); pwszOID=NULL; } }
} else { //we need to build the extension list for the certificate types
dwExtensions=0; for(dwIndex=0; dwIndex<pCertCA->dwCertTypeInfo; dwIndex++) { if(TRUE==(pCertCA->rgCertTypeInfo)[dwIndex].fSelected) { //add the extensions
if(NULL !=(pCertCA->rgCertTypeInfo)[dwIndex].pCertTypeExtensions) { dwExtensions++; pExtensions=(PCERT_EXTENSIONS *)WizardRealloc(pExtensions, dwExtensions * sizeof(PCERT_EXTENSIONS)); _JumpCondition(NULL == pExtensions, MemoryError); pExtensions[dwExtensions-1]=(pCertCA->rgCertTypeInfo)[dwIndex].pCertTypeExtensions; } pCertWizardInfo->dwEnrollmentFlags = (pCertCA->rgCertTypeInfo)[dwIndex].dwEnrollmentFlags; pCertWizardInfo->dwSubjectNameFlags = (pCertCA->rgCertTypeInfo)[dwIndex].dwSubjectNameFlags; pCertWizardInfo->dwPrivateKeyFlags = (pCertCA->rgCertTypeInfo)[dwIndex].dwPrivateKeyFlags; pCertWizardInfo->dwGeneralFlags = (pCertCA->rgCertTypeInfo)[dwIndex].dwGeneralFlags; //copy the dwKeySpec and genKeyFlags from the
//cert type to the request information
//if rgdwCSP is not NULL for the cert type, then we know
//we need to copy the information since the memory is always
//allocated
if((pCertCA->rgCertTypeInfo)[dwIndex].rgdwCSP) { //if ignored the user's input, we use the one from the certificate
//template
if(TRUE == pCertWizardInfo->fIgnore) { pCertWizardInfo->dwKeySpec=(pCertCA->rgCertTypeInfo)[dwIndex].dwKeySpec; if (!CertTypeFlagsToGenKeyFlags (pCertWizardInfo->dwEnrollmentFlags, pCertWizardInfo->dwSubjectNameFlags, pCertWizardInfo->dwPrivateKeyFlags, pCertWizardInfo->dwGeneralFlags, &dwGenKeyFlags)) goto CertTypeFlagsToGenKeyFlagsError; // Add these flags to whatever flags have already been specified by the user.
pCertWizardInfo->dwGenKeyFlags |= dwGenKeyFlags; pCertWizardInfo->dwGenKeyFlags |= ((pCertCA->rgCertTypeInfo)[dwIndex].dwMinKeySize << 16); } else { //we only copy information we need to
if(0 == pCertWizardInfo->dwKeySpec) pCertWizardInfo->dwKeySpec=(pCertCA->rgCertTypeInfo)[dwIndex].dwKeySpec; } } // The user has specified a minimum key size through the advanced options.
// Use it to override whatever key size is specified in the cert template.
if (pCertWizardInfo->dwMinKeySize != 0) { pCertWizardInfo->dwGenKeyFlags &= 0x0000FFFF; pCertWizardInfo->dwGenKeyFlags |= (pCertWizardInfo->dwMinKeySize) << 16; } //deside the CSP to use:
if(NULL == pCertWizardInfo->pwszProvider) { if((pCertCA->rgCertTypeInfo)[dwIndex].dwCSPCount && (pCertCA->rgCertTypeInfo)[dwIndex].rgdwCSP) { //Use the 1st one on the cert type's CSP list
pCertWizardInfo->pwszProvider=pCertWizardInfo->rgwszProvider[dwCSPIndex]; pCertWizardInfo->dwProviderType=pCertWizardInfo->rgdwProviderType[dwCSPIndex]; fRevertWizardProvider = TRUE; } }
//the increase the min key size to the minimal of CSP selected
if(GetValidKeySizes( pCertWizardInfo->pwszProvider, pCertWizardInfo->dwProviderType, pCertWizardInfo->dwKeySpec, &dwMinKey, &dwMaxKey, &dwInc)) { dwTempGenKeyFlags = pCertWizardInfo->dwGenKeyFlags;
dwTempGenKeyFlags &= 0xFFFF0000;
dwTempGenKeyFlags = (dwTempGenKeyFlags >> 16);
//we use 0 for default key size for V1 template
if(0 != dwTempGenKeyFlags) { if(dwTempGenKeyFlags < dwMinKey) { pCertWizardInfo->dwGenKeyFlags &= 0x0000FFFF; pCertWizardInfo->dwGenKeyFlags |= ((dwMinKey) << 16); } } } } } }
//user has to set up the CSP:
//1. in the UI case. The CSP is always selected
//2. In the UILess case, the CSP can be:
// 2.1 User specified in the API.
// 2.2 We have selected for their dehalf for the CSP list on the cert template
// 2.3 We default to RSA_FULL for non-cert template case
if((NULL == pCertWizardInfo->pwszProvider) || (0 == pCertWizardInfo->dwProviderType)) { idsText=IDS_ENROLL_NO_CERT_TYPE; hr=E_INVALIDARG; }
//consider the user input extensions
if(pCertWizardInfo->pCertRequestExtensions) { dwExtensions++; pExtensions=(PCERT_EXTENSIONS *)WizardRealloc(pExtensions, dwExtensions * sizeof(PCERT_EXTENSIONS)); _JumpCondition(NULL == pExtensions, MemoryError);
pExtensions[dwExtensions-1]=pCertWizardInfo->pCertRequestExtensions; }
//set up the private key information
pCertRequestPvkNew->dwSize=sizeof(CERT_REQUEST_PVK_NEW); pCertRequestPvkNew->dwProvType=pCertWizardInfo->dwProviderType; pCertRequestPvkNew->pwszProvider=pCertWizardInfo->pwszProvider; pCertRequestPvkNew->dwProviderFlags=pCertWizardInfo->dwProviderFlags;
//we mark the provider flag SILENT for remote or UIless enrollment
if (((0 != (pCertWizardInfo->dwFlags & CRYPTUI_WIZ_NO_UI)) && (0 == (pCertWizardInfo->dwFlags & CRYPTUI_WIZ_IGNORE_NO_UI_FLAG_FOR_CSPS))) || (FALSE == pCertWizardInfo->fLocal)) { pCertRequestPvkNew->dwProviderFlags |= CRYPT_SILENT; }
pCertRequestPvkNew->pwszKeyContainer = pCertWizardInfo->pwszKeyContainer; pCertRequestPvkNew->dwKeySpec = pCertWizardInfo->dwKeySpec; pCertRequestPvkNew->dwGenKeyFlags = pCertWizardInfo->dwGenKeyFlags;
pCertRequestPvkNew->dwEnrollmentFlags = pCertWizardInfo->dwEnrollmentFlags; pCertRequestPvkNew->dwSubjectNameFlags = pCertWizardInfo->dwSubjectNameFlags; pCertRequestPvkNew->dwPrivateKeyFlags = pCertWizardInfo->dwPrivateKeyFlags; pCertRequestPvkNew->dwGeneralFlags = pCertWizardInfo->dwGeneralFlags;
//set up the enrollment information
pRequestInfo->dwSize=sizeof(CERT_ENROLL_INFO); pRequestInfo->pwszUsageOID=pwszUsageOID;
pRequestInfo->pwszCertDNName=pCertWizardInfo->pwszCertDNName;
pRequestInfo->dwPostOption=pCertWizardInfo->dwPostOption;
pRequestInfo->dwExtensions=dwExtensions; pRequestInfo->prgExtensions=pExtensions;
// We want to copy the friendlyname and description from the request info if
// a) if we're enrolling OR
// b) if we're enrolling with a signing cert
fCopyPropertiesFromRequestInfo = (0 != (CRYPTUI_WIZ_CERT_ENROLL & pCertWizardInfo->dwPurpose)) || (0 != (CRYPTUI_WIZ_NO_ARCHIVE_RENEW_CERT & pCertWizardInfo->dwFlags)); //set up the friendlyName and pwszDescription separately
if (fCopyPropertiesFromRequestInfo) { if (NULL == pCertWizardInfo->pwszFriendlyName) { pRequestInfo->pwszFriendlyName = NULL; } else { pRequestInfo->pwszFriendlyName = WizardAllocAndCopyWStr(pCertWizardInfo->pwszFriendlyName); _JumpCondition(NULL == pRequestInfo->pwszFriendlyName, MemoryError); }
if (NULL == pCertWizardInfo->pwszDescription) { pRequestInfo->pwszDescription = NULL; } else { pRequestInfo->pwszDescription = WizardAllocAndCopyWStr(pCertWizardInfo->pwszDescription); _JumpCondition(NULL == pRequestInfo->pwszDescription, MemoryError); } } else // copy properties from renew cert context
{ //get the friendlyName and description of the cerititificate
//get the friendly info from the certificate
CertAllocAndGetCertificateContextProperty (pCertWizardInfo->pCertContext, CERT_FRIENDLY_NAME_PROP_ID, (LPVOID *)&(pRequestInfo->pwszFriendlyName), &dwSize);
//get the description
CertAllocAndGetCertificateContextProperty (pCertWizardInfo->pCertContext, CERT_DESCRIPTION_PROP_ID, (LPVOID *)&(pRequestInfo->pwszDescription), &dwSize); }
// We want to set up renew pvk info if
// a) We're renewing
// b) We're enrolling with a signing cert
fSetUpRenewPvk = (0 == (CRYPTUI_WIZ_CERT_ENROLL & pCertWizardInfo->dwPurpose)) || (0 != (CRYPTUI_WIZ_NO_ARCHIVE_RENEW_CERT & pCertWizardInfo->dwFlags));
if (fSetUpRenewPvk) { //Set up the private key information and the certBLOBs
_JumpCondition(NULL == pCertWizardInfo->pCertContext, InvalidArgError);
pCertBlob->cbData=pCertWizardInfo->pCertContext->cbCertEncoded; pCertBlob->pbData=pCertWizardInfo->pCertContext->pbCertEncoded;
//get the private key info from the certificate
if(!CertAllocAndGetCertificateContextProperty (pCertWizardInfo->pCertContext, CERT_KEY_PROV_INFO_PROP_ID, (LPVOID *)&pKeyProvInfo, &dwSize)) goto CertAllocAndGetCertificateContextPropertyError;
//set up the private key information
pCertRenewPvk->dwSize = sizeof(CERT_REQUEST_PVK_NEW); pCertRenewPvk->dwProvType = pKeyProvInfo->dwProvType; pCertRenewPvk->dwProviderFlags = pKeyProvInfo->dwFlags;
//we mark the provider flag SILENT for remote or UIless enrollment
if (((0 != (pCertWizardInfo->dwFlags & CRYPTUI_WIZ_NO_UI)) && (0 == (pCertWizardInfo->dwFlags & CRYPTUI_WIZ_IGNORE_NO_UI_FLAG_FOR_CSPS))) || (FALSE == pCertWizardInfo->fLocal)) { pCertRenewPvk->dwProviderFlags |= CRYPT_SILENT; }
pCertRenewPvk->dwKeySpec = pKeyProvInfo->dwKeySpec; pCertRenewPvk->dwEnrollmentFlags = pCertWizardInfo->dwEnrollmentFlags; pCertRenewPvk->dwSubjectNameFlags = pCertWizardInfo->dwSubjectNameFlags; pCertRenewPvk->dwPrivateKeyFlags = pCertWizardInfo->dwPrivateKeyFlags; pCertRenewPvk->dwGeneralFlags = pCertWizardInfo->dwGeneralFlags;
pCertRenewPvk->pwszKeyContainer = WizardAllocAndCopyWStr( pKeyProvInfo->pwszContainerName); _JumpCondition(NULL == pCertRenewPvk->pwszKeyContainer, MemoryError);
pCertRenewPvk->pwszProvider = WizardAllocAndCopyWStr( pKeyProvInfo->pwszProvName); _JumpCondition(NULL == pCertRenewPvk->pwszProvider, MemoryError); }
hr = S_OK;
CLEANUP: if (fRevertWizardProvider) { pCertWizardInfo->pwszProvider = NULL; }
if (S_OK != hr) { pCertWizardInfo->idsText = idsText; pCertWizardInfo->dwStatus = CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR; }
if (NULL != pwszOID) { FreeWStr(pwszOID); } if (NULL != pKeyProvInfo) { WizardFree((LPVOID)pKeyProvInfo); }
return hr;
ErrorReturn: goto CLEANUP;
SET_HRESULT(CertAllocAndGetCertificateContextPropertyError, CodeToHR(GetLastError())); SET_HRESULT(CertTypeFlagsToGenKeyFlagsError, CodeToHR(GetLastError())); SET_HRESULT(InvalidArgError, E_INVALIDARG); SET_HRESULT(MemoryError, E_OUTOFMEMORY); SET_HRESULT(UnexpectedError, E_UNEXPECTED); }
void FreeRequestParameters(IN LPWSTR *ppwszHashAlg, IN CERT_REQUEST_PVK_NEW *pCertRenewPvk, IN CERT_ENROLL_INFO *pRequestInfo)
{ if (NULL != pRequestInfo) { if (NULL != pRequestInfo->pwszUsageOID) { WizardFree((LPVOID)pRequestInfo->pwszUsageOID); } if (NULL != pRequestInfo->prgExtensions) { WizardFree((LPVOID)pRequestInfo->prgExtensions); } if (NULL != pRequestInfo->pwszFriendlyName) { WizardFree((LPVOID)pRequestInfo->pwszFriendlyName); } if (NULL != pRequestInfo->pwszDescription) { WizardFree((LPVOID)pRequestInfo->pwszDescription); }
pRequestInfo->pwszUsageOID = NULL; pRequestInfo->prgExtensions = NULL; pRequestInfo->pwszFriendlyName = NULL; pRequestInfo->pwszDescription = NULL; }
if (NULL != pCertRenewPvk) { if (NULL != pCertRenewPvk->pwszKeyContainer) { WizardFree((LPVOID)pCertRenewPvk->pwszKeyContainer); pCertRenewPvk->pwszKeyContainer = NULL; }
if (NULL != pCertRenewPvk->pwszProvider) { WizardFree((LPVOID)pCertRenewPvk->pwszProvider); pCertRenewPvk->pwszProvider = NULL; } }
if (NULL != ppwszHashAlg && NULL != *ppwszHashAlg) { FreeWStr(*ppwszHashAlg); *ppwszHashAlg = NULL; } }
//-----------------------------------------------------------------------------
// Memory routines
//
//#define malloc(cb) ((void*)LocalAlloc(LPTR, cb))
//#define free(pv) (LocalFree((HLOCAL)pv))
//#define realloc(pv, cb) ((void*)LocalReAlloc((HLOCAL)pv, cb, LMEM_MOVEABLE))
//
//
//-----------------------------------------------------------------------------
LPVOID WizardAlloc (ULONG cbSize) { return ((void*)LocalAlloc(LPTR, cbSize)); }
LPVOID WizardRealloc ( LPVOID pv, ULONG cbSize) { LPVOID pvTemp=NULL;
if(NULL==pv) return WizardAlloc(cbSize);
pvTemp=((void*)LocalReAlloc((HLOCAL)pv, cbSize, LMEM_MOVEABLE));
if(NULL==pvTemp) { //we are running out memory
WizardFree(pv); }
return pvTemp; }
VOID MyWizardFree (LPVOID pv) { if (pv) LocalFree((HLOCAL)pv); }
VOID WizardFree (LPVOID pv) { if (pv) LocalFree((HLOCAL)pv); }
//-----------------------------------------------------------------------------
// the call back function to compare the certificate
//
//-----------------------------------------------------------------------------
int CALLBACK CompareCertificate(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { PCCERT_CONTEXT pCertOne=NULL; PCCERT_CONTEXT pCertTwo=NULL; DWORD dwColumn=0; int iCompare=0; LPWSTR pwszOne=NULL; LPWSTR pwszTwo=NULL;
pCertOne=(PCCERT_CONTEXT)lParam1; pCertTwo=(PCCERT_CONTEXT)lParam2; dwColumn=(DWORD)lParamSort;
if((NULL==pCertOne) || (NULL==pCertTwo)) goto CLEANUP;
switch(dwColumn & 0x0000FFFF) { case SORT_COLUMN_SUBJECT: GetCertSubject(pCertOne, &pwszOne); GetCertSubject(pCertTwo, &pwszTwo); break; case SORT_COLUMN_ISSUER: GetCertIssuer(pCertOne, &pwszOne); GetCertIssuer(pCertTwo, &pwszTwo); break;
case SORT_COLUMN_PURPOSE: GetCertPurpose(pCertOne, &pwszOne); GetCertPurpose(pCertTwo, &pwszTwo); break;
case SORT_COLUMN_NAME: GetCertFriendlyName(pCertOne, &pwszOne); GetCertFriendlyName(pCertTwo, &pwszTwo); break;
case SORT_COLUMN_LOCATION: if (!GetCertLocation(pCertOne, &pwszOne)) { pwszOne = NULL; goto CLEANUP; } if (!GetCertLocation(pCertTwo, &pwszTwo)) { pwszTwo = NULL; goto CLEANUP; } break; }
if(SORT_COLUMN_EXPIRATION == (dwColumn & 0x0000FFFF)) { iCompare=CompareFileTime(&(pCertOne->pCertInfo->NotAfter), &(pCertTwo->pCertInfo->NotAfter));
} else { if((NULL==pwszOne) || (NULL==pwszTwo)) goto CLEANUP;
//we should use wcsicoll instead of wcsicmp since wcsicoll use the
//lexicographic order of current code page.
iCompare=CompareStringU(LOCALE_USER_DEFAULT, NORM_IGNORECASE, pwszOne, -1, pwszTwo, -1);
//map to the C run time convention
iCompare = iCompare -2; }
if(dwColumn & SORT_COLUMN_DESCEND) iCompare = 0-iCompare;
CLEANUP:
if(pwszOne) WizardFree(pwszOne);
if(pwszTwo) WizardFree(pwszTwo);
return iCompare; }
//-----------------------------------------------------------------------------
// GetCertIssuer
//
//-----------------------------------------------------------------------------
BOOL GetCertIssuer(PCCERT_CONTEXT pCertContext, LPWSTR *ppwsz) { BOOL fResult=FALSE; DWORD dwChar=0; WCHAR wszNone[MAX_TITLE_LENGTH];
if(!pCertContext || !ppwsz) goto CLEANUP;
*ppwsz=NULL;
dwChar=CertGetNameStringW( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, NULL, 0);
if ((dwChar != 0) && (NULL != (*ppwsz = (LPWSTR)WizardAlloc(dwChar * sizeof(WCHAR))))) {
CertGetNameStringW( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, CERT_NAME_ISSUER_FLAG, NULL, *ppwsz, dwChar);
} else { if(!LoadStringU(g_hmodThisDll, IDS_NONE, wszNone, MAX_TITLE_LENGTH)) wszNone[0]=L'\0';
if(!(*ppwsz=WizardAllocAndCopyWStr(wszNone))) goto CLEANUP; }
fResult=TRUE;
CLEANUP:
if(FALSE == fResult) { if(*ppwsz) WizardFree(*ppwsz);
*ppwsz=NULL; }
return fResult;
}
//-----------------------------------------------------------------------------
// GetCertSubject
//
//-----------------------------------------------------------------------------
BOOL GetCertSubject(PCCERT_CONTEXT pCertContext, LPWSTR *ppwsz) { BOOL fResult=FALSE; DWORD dwChar=0; WCHAR wszNone[MAX_TITLE_LENGTH];
if(!pCertContext || !ppwsz) goto CLEANUP;
*ppwsz=NULL;
dwChar=CertGetNameStringW( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, NULL, 0);
if ((dwChar != 0) && (NULL != (*ppwsz = (LPWSTR)WizardAlloc(dwChar * sizeof(WCHAR))))) {
CertGetNameStringW( pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, NULL, *ppwsz, dwChar);
} else { if(!LoadStringU(g_hmodThisDll, IDS_NONE, wszNone, MAX_TITLE_LENGTH)) wszNone[0]=L'\0';
if(!(*ppwsz=WizardAllocAndCopyWStr(wszNone))) goto CLEANUP; }
fResult=TRUE;
CLEANUP:
if(FALSE == fResult) { if(*ppwsz) WizardFree(*ppwsz);
*ppwsz=NULL; }
return fResult;
}
//-----------------------------------------------------------------------------
// MyFormatEnhancedKeyUsageString
//
// This functions is here because the FormatEnhancedKeyUsageString function
// uses malloc and all the wizards use LocalAlloc and LocalFree.
//
//-----------------------------------------------------------------------------
BOOL MyFormatEnhancedKeyUsageString(LPWSTR *ppString, PCCERT_CONTEXT pCertContext, BOOL fPropertiesOnly, BOOL fMultiline) { LPWSTR pwszTemp = NULL;
if(!FormatEnhancedKeyUsageString(&pwszTemp, pCertContext, fPropertiesOnly, fMultiline)) return FALSE; *ppString = WizardAllocAndCopyWStr(pwszTemp);
free(pwszTemp);
if (*ppString != NULL) return TRUE; else return FALSE; } //-----------------------------------------------------------------------------
// GetCertPurpose
//
//-----------------------------------------------------------------------------
BOOL GetCertPurpose(PCCERT_CONTEXT pCertContext, LPWSTR *ppwsz) { if(!pCertContext || !ppwsz) return FALSE;
*ppwsz=NULL;
if(MyFormatEnhancedKeyUsageString(ppwsz,pCertContext, FALSE, FALSE)) return TRUE;
return FALSE; }
//-----------------------------------------------------------------------------
// GetCertFriendlyName
//
//-----------------------------------------------------------------------------
BOOL GetCertFriendlyName(PCCERT_CONTEXT pCertContext, LPWSTR *ppwsz) { DWORD dwChar=0; WCHAR wszNone[MAX_TITLE_LENGTH];
if(!pCertContext || !ppwsz) return FALSE;
*ppwsz=NULL;
dwChar=0;
if(CertAllocAndGetCertificateContextProperty( pCertContext, CERT_FRIENDLY_NAME_PROP_ID, (LPVOID *)ppwsz, &dwChar)) { return TRUE; }
if(!LoadStringU(g_hmodThisDll, IDS_NONE, wszNone, MAX_TITLE_LENGTH)) wszNone[0]=L'\0';
if((*ppwsz=WizardAllocAndCopyWStr(wszNone))) return TRUE;
return FALSE; }
//-----------------------------------------------------------------------------
// GetCertLocation
//
//-----------------------------------------------------------------------------
BOOL GetCertLocation (PCCERT_CONTEXT pCertContext, LPWSTR *ppwsz) { DWORD cbName = 0; WCHAR wszNotAvailable[MAX_TITLE_LENGTH]; if (CertGetStoreProperty( pCertContext->hCertStore, CERT_STORE_LOCALIZED_NAME_PROP_ID, NULL, &cbName)) { if (NULL == (*ppwsz = (LPWSTR) WizardAlloc(cbName))) { return FALSE; }
if (!CertGetStoreProperty( pCertContext->hCertStore, CERT_STORE_LOCALIZED_NAME_PROP_ID, *ppwsz, &cbName)) { WizardFree(*ppwsz); return FALSE; } } else { if (!LoadStringU(g_hmodThisDll, IDS_NOTAVAILABLE, wszNotAvailable, MAX_TITLE_LENGTH)) { wszNotAvailable[0]=L'\0'; }
if (NULL == (*ppwsz = WizardAllocAndCopyWStr(wszNotAvailable))) { return FALSE; } }
return TRUE; }
//-----------------------------------------------------------------------------
// LoadFilterString
//
//-----------------------------------------------------------------------------
int LoadFilterString( HINSTANCE hInstance, UINT uID, LPWSTR lpBuffer, int nBufferMax) { int size;
if(size = LoadStringU(hInstance, uID, lpBuffer, nBufferMax-1)) { lpBuffer[size]= L'\0'; lpBuffer[size+1]= L'\0'; return size+1; } else { return 0; } }
//-----------------------------------------------------------------------------
// ExpandAndAllocString
//
//-----------------------------------------------------------------------------
LPWSTR ExpandAndAllocString(LPCWSTR pwsz) { LPWSTR pwszExpandedFileName = NULL; DWORD dwExpanded = 0;
dwExpanded = ExpandEnvironmentStringsU(pwsz, NULL, 0); pwszExpandedFileName = (LPWSTR) WizardAlloc(dwExpanded * sizeof(WCHAR)); if (pwszExpandedFileName == NULL) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return (NULL); }
if (0 == ExpandEnvironmentStringsU(pwsz, pwszExpandedFileName, dwExpanded)) { WizardFree(pwszExpandedFileName); return (NULL); }
return (pwszExpandedFileName); }
//-----------------------------------------------------------------------------
// ExpandAndCreateFileU
//
//-----------------------------------------------------------------------------
HANDLE WINAPI ExpandAndCreateFileU ( LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile ) { HANDLE hRet = INVALID_HANDLE_VALUE; LPWSTR pwszExpandedFileName = NULL; pwszExpandedFileName = ExpandAndAllocString(lpFileName);
if (NULL != pwszExpandedFileName) { hRet = CreateFileU ( pwszExpandedFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); WizardFree(pwszExpandedFileName); }
return (hRet); }
WINCRYPT32API BOOL WINAPI ExpandAndCryptQueryObject( DWORD dwObjectType, const void *pvObject, DWORD dwExpectedContentTypeFlags, DWORD dwExpectedFormatTypeFlags, DWORD dwFlags, DWORD *pdwMsgAndCertEncodingType, DWORD *pdwContentType, DWORD *pdwFormatType, HCERTSTORE *phCertStore, HCRYPTMSG *phMsg, const void **ppvContext ) { LPWSTR pwszExpandedFileName = NULL; BOOL fRet = FALSE; if (dwObjectType == CERT_QUERY_OBJECT_FILE) { pwszExpandedFileName = ExpandAndAllocString((LPWSTR)pvObject);
if (NULL != pwszExpandedFileName) { fRet = CryptQueryObject( dwObjectType, pwszExpandedFileName, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext ); WizardFree(pwszExpandedFileName); } else { fRet = FALSE; } } else { fRet = CryptQueryObject( dwObjectType, pvObject, dwExpectedContentTypeFlags, dwExpectedFormatTypeFlags, dwFlags, pdwMsgAndCertEncodingType, pdwContentType, pdwFormatType, phCertStore, phMsg, ppvContext ); } return (fRet); }
HRESULT EnrollmentCOMObjectFactory_getInstance (EnrollmentCOMObjectFactoryContext *pContext, REFCLSID rclsid, REFIID riid, LPUNKNOWN *pUnknown, LPVOID *ppInstance) { HRESULT hr = S_OK; // Input validation.
// Only ppInstance can be an invalid argument, as the other arguments are supplied
// directly by other class members.
if (ppInstance == NULL) { return E_INVALIDARG; } // Ensure that COM is initialized.
if (!pContext->fIsCOMInitialized) { hr = CoInitialize(NULL); if (FAILED(hr)) goto Error; pContext->fIsCOMInitialized = TRUE; } if (*pUnknown == NULL) { // We've not yet created an instance of this type, do so now:
if (S_OK != (hr = CoCreateInstance(rclsid, NULL, CLSCTX_INPROC_SERVER, riid, (LPVOID *)pUnknown))) goto Error; } // Increment the reference count and assign the out param:
(*pUnknown)->AddRef(); *ppInstance = *pUnknown;
CommonReturn: return hr;
Error: // Some error occured which did not prevent the creation of the COM object.
// Release the object:
if (*pUnknown != NULL) { (*pUnknown)->Release(); *pUnknown = NULL; }
goto CommonReturn; }
//-----------------------------------------------------------------------
//
// RetrivePKCS7FromCA
//
// The routine that calls xEnroll and CA to request a certificate
// This routine also provide confirmation dialogue
//------------------------------------------------------------------------
extern "C" HRESULT WINAPI RetrievePKCS7FromCA(DWORD dwPurpose, LPWSTR pwszCALocation, LPWSTR pwszCAName, LPWSTR pwszRequestString, CRYPT_DATA_BLOB *pPKCS10Blob, CRYPT_DATA_BLOB *pPKCS7Blob, DWORD *pdwStatus) { HRESULT hr=E_FAIL; DWORD dwException=0; DWORD dwStatus=0; DWORD dwDisposition=0; DWORD dwFlags=0;
CERTSERVERENROLL *pCertServerEnroll=NULL;
//input checking
if(!pPKCS10Blob || !pPKCS7Blob) return E_INVALIDARG;
//determine the format flag
if(dwPurpose & CRYPTUI_WIZ_CERT_RENEW ) dwFlags = CR_IN_BINARY | CR_IN_PKCS7; else dwFlags = CR_IN_BINARY | CR_IN_PKCS10;
//submit the request
__try { hr= CertServerSubmitRequest( dwFlags, pPKCS10Blob->pbData, pPKCS10Blob->cbData, pwszRequestString, pwszCALocation, pwszCAName, &pCertServerEnroll); } __except(dwException = GetExceptionCode(), EXCEPTION_EXECUTE_HANDLER) { hr=HRESULT_FROM_WIN32(dwException);
if(S_OK == hr) hr=E_UNEXPECTED; }
//process the error
//first, filter out the PRC error
if(hr == HRESULT_FROM_WIN32(RPC_S_UNKNOWN_AUTHN_SERVICE) || hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) || hr == HRESULT_FROM_WIN32(RPC_S_SERVER_TOO_BUSY)) { dwStatus=CRYPTUI_WIZ_CERT_REQUEST_STATUS_CONNECTION_FAILED; goto CLEANUP; }
//if hr is S_OK, we have retrieve valid return from the CA
if(hr==S_OK) { if(!pCertServerEnroll) { hr=E_INVALIDARG; dwDisposition=CR_DISP_ERROR; } else { hr = pCertServerEnroll->hrLastStatus; dwDisposition = pCertServerEnroll->Disposition; } } else { dwDisposition=CR_DISP_ERROR; }
//map the dwDisposition to dwStatus
switch(dwDisposition) { case CR_DISP_DENIED: dwStatus=CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_DENIED;
if(!FAILED(hr)) hr=E_FAIL;
break;
case CR_DISP_ISSUED: dwStatus=CRYPTUI_WIZ_CERT_REQUEST_STATUS_CERT_ISSUED; break;
case CR_DISP_ISSUED_OUT_OF_BAND: dwStatus=CRYPTUI_WIZ_CERT_REQUEST_STATUS_ISSUED_SEPARATELY; break;
case CR_DISP_UNDER_SUBMISSION: dwStatus=CRYPTUI_WIZ_CERT_REQUEST_STATUS_UNDER_SUBMISSION; break;
//we should never get CR_DISP_INCOMPLETE or CR_DISP_REVOKED
//case CR_DISP_INCOMPLETE:
//case CR_DISP_REVOKED:
case CR_DISP_ERROR: default: dwStatus=CRYPTUI_WIZ_CERT_REQUEST_STATUS_REQUEST_ERROR;
if(!FAILED(hr)) hr=E_FAIL; break; }
//no need to retrieve the enrolled certificate if failed
if(hr != S_OK) goto CLEANUP;
//copy the PKCS7 blob
pPKCS7Blob->cbData=pCertServerEnroll->cbCertChain;
pPKCS7Blob->pbData=(BYTE *)WizardAlloc(pCertServerEnroll->cbCertChain);
if(NULL==pPKCS7Blob->pbData) { hr=E_OUTOFMEMORY; dwStatus=CRYPTUI_WIZ_CERT_REQUEST_STATUS_INSTALL_FAILED; goto CLEANUP; }
memcpy(pPKCS7Blob->pbData,pCertServerEnroll->pbCertChain,pCertServerEnroll->cbCertChain);
hr=S_OK;
CLEANUP:
if(pCertServerEnroll) CertServerFreeMemory(pCertServerEnroll);
if(pdwStatus) *pdwStatus=dwStatus; return hr; }
IEnumCSP::IEnumCSP(CERT_WIZARD_INFO * pCertWizardInfo) { if (NULL == pCertWizardInfo) { m_hr = E_POINTER; return; // We're not initialized.
}
m_fIsInitialized = FALSE; m_cCSPs = pCertWizardInfo->dwCSPCount; m_pfCSPs = (BOOL *)WizardAlloc(sizeof(BOOL) * m_cCSPs); if (NULL == m_pfCSPs) { m_hr = E_OUTOFMEMORY; return; // We're not initialized.
} if (NULL != pCertWizardInfo->pwszProvider) { for (DWORD dwIndex = 0; dwIndex < pCertWizardInfo->dwCSPCount; dwIndex++) { if (0 == _wcsicmp(pCertWizardInfo->pwszProvider, pCertWizardInfo->rgwszProvider[dwIndex])) { // Enable only the CSP we've specified.
m_pfCSPs[dwIndex] = TRUE; } } } else { for (DWORD dwCAIndex = 1; dwCAIndex < pCertWizardInfo->pCertCAInfo->dwCA; dwCAIndex++ ) { CRYPTUI_WIZ_CERT_CA *pCertCA = &(pCertWizardInfo->pCertCAInfo->rgCA[dwCAIndex]);
// Any cert types available for this CA?
if(pCertCA->dwCertTypeInfo > 0) { for(DWORD dwCertTypeIndex = 0; dwCertTypeIndex < pCertCA->dwCertTypeInfo; dwCertTypeIndex++) { if (TRUE == (pCertCA->rgCertTypeInfo)[dwCertTypeIndex].fSelected) { if ((pCertCA->rgCertTypeInfo)[dwCertTypeIndex].dwCSPCount && (pCertCA->rgCertTypeInfo)[dwCertTypeIndex].rgdwCSP) { for (DWORD dwCSPIndex = 0; dwCSPIndex < (pCertCA->rgCertTypeInfo)[dwCertTypeIndex].dwCSPCount; dwCSPIndex++) { // Turn on this CSP.
m_pfCSPs[((pCertCA->rgCertTypeInfo)[dwCertTypeIndex].rgdwCSP)[dwCSPIndex]] = TRUE; } } } } } } }
m_dwCSPIndex = 0; m_fIsInitialized = TRUE; }
HRESULT IEnumCSP::HasNext(BOOL *pfResult) { if (FALSE == m_fIsInitialized) return m_hr;
for (; m_dwCSPIndex < m_cCSPs; m_dwCSPIndex++) { if (m_pfCSPs[m_dwCSPIndex]) { *pfResult = TRUE; return S_OK; } } *pfResult = FALSE; return S_OK; }
HRESULT IEnumCSP::Next(DWORD *pdwCSP) { if (FALSE == m_fIsInitialized) return m_hr;
if (NULL == pdwCSP) return E_INVALIDARG; for (; m_dwCSPIndex < m_cCSPs; m_dwCSPIndex++) { if (m_pfCSPs[m_dwCSPIndex]) { *pdwCSP = m_dwCSPIndex++; return S_OK; } } return HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND); }
HRESULT IEnumCA::HasNext(BOOL *pfResult) { BOOL fDontKnowCA;
if (NULL == pfResult) return E_INVALIDARG;
// We don't know the CA if it wasn't supplied through the API,
// and if the user did not specify it through advanced options.
fDontKnowCA = FALSE == m_pCertWizardInfo->fCAInput; fDontKnowCA &= FALSE == m_pCertWizardInfo->fUIAdv;
if (FALSE == fDontKnowCA) { *pfResult = m_dwCAIndex == 1; return S_OK; } else { for (; m_dwCAIndex < m_pCertWizardInfo->pCertCAInfo->dwCA; m_dwCAIndex++) { if (CASupportSpecifiedCertType(&(m_pCertWizardInfo->pCertCAInfo->rgCA[m_dwCAIndex]))) { *pfResult = TRUE; return S_OK; } } }
*pfResult = FALSE; return S_OK; }
HRESULT IEnumCA::Next(PCRYPTUI_WIZ_CERT_CA pCertCA) { BOOL fDontKnowCA;
if (NULL == pCertCA) return E_INVALIDARG;
// We don't know the CA if it wasn't supplied through the API,
// and if the user did not specify it through advanced options.
fDontKnowCA = FALSE == m_pCertWizardInfo->fCAInput; fDontKnowCA &= FALSE == m_pCertWizardInfo->fUIAdv;
if (FALSE == fDontKnowCA) { if (1 == m_dwCAIndex) { CRYPTUI_WIZ_CERT_CA CertCA; m_dwCAIndex++; CertCA.pwszCALocation = m_pCertWizardInfo->pwszCALocation; CertCA.pwszCAName = m_pCertWizardInfo->pwszCAName; *pCertCA = CertCA; return S_OK; } } else { for (; m_dwCAIndex < m_pCertWizardInfo->pCertCAInfo->dwCA; m_dwCAIndex++) { if (CASupportSpecifiedCertType(&(m_pCertWizardInfo->pCertCAInfo->rgCA[m_dwCAIndex]))) { *pCertCA = m_pCertWizardInfo->pCertCAInfo->rgCA[m_dwCAIndex++]; return S_OK; } } }
return HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND); }
|