//-------------------------------------------------------------- // 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 #include #include "xenroll.h" #include "xenroll_i.c" #include #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; dwIndexgetICertRequest2(&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; } if (NULL != varExchangeCertificate.bstrVal) { SysFreeString(varExchangeCertificate.bstrVal); } 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); SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0); 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; dwIndexcExtension; 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; dwUsagecUsageIdentifier; 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); 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 = L"CA"; // 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())); } HRESULT WINAPI SubmitRequest(IN HANDLE hRequest, IN BOOL fKeyService, //IN Required: Whether the function is called remotely IN DWORD dwPurpose, //IN Required: Whether it is enrollment or renew IN BOOL fConfirmation, //IN Required: Set the TRUE if confirmation dialogue is needed IN HWND hwndParent, //IN Optional: The parent window IN LPWSTR pwszConfirmationTitle, //IN Optional: The title for confirmation dialogue IN UINT idsConfirmTitle, //IN Optional: The resource ID for the title of the confirmation dialogue 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 dwIndex = 0; // Temporary variable. 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; LPVOID *ppvRequest = NULL; 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; PCRYPT_DATA_BLOB pPKCS10Request = NULL; // A pointer to the supplied PKCS10 request. 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 = NULL; // 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); } 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, pwszCADisplayName ? pwszCADisplayName : 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; dwIndexdwOIDInfo; 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; dwIndexdwCertTypeInfo; 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_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 != 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) { WCHAR wszNone[MAX_TITLE_LENGTH]; 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) { BOOL fResult=FALSE; 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)) { 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(E_OUTOFMEMORY); 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_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); }