//depot/Lab03_DEV/Ds/security/cryptoapi/pki/activex/xenroll/cenroll.cpp#4 - edit change 19979 (text) //+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: cenroll.cpp // //-------------------------------------------------------------------------- // CEnroll.cpp : Implementation of CCEnroll #include "stdafx.h" #include #include #include #define SECURITY_WIN32 #include #include #include #include #include #include #include #include "xenroll.h" #include "cenroll.h" #include "xelib.h" #include "sfscript.h" #define NO_OSS_DEBUG #include #include #include static LPVOID (* MyCoTaskMemAlloc)(ULONG) = NULL; static LPVOID (* MyCoTaskMemRealloc)(LPVOID, ULONG) = NULL; static void (* MyCoTaskMemFree)(LPVOID) = NULL; #define MY_HRESULT_FROM_WIN32(a) ((a >= 0x80000000) ? a : HRESULT_FROM_WIN32(a)) #ifndef NTE_TOKEN_KEYSET_STORAGE_FULL #define NTE_TOKEN_KEYSET_STORAGE_FULL _HRESULT_TYPEDEF_(0x80090023L) #endif #define CEnrollLocalScope(ScopeName) struct ScopeName##TheLocalScope { public #define CEnrollEndLocalScope } local #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0])) #pragma warning(disable:4213) // nonstandard extension used : cast on l-value static LPSTR MBFromWide(LPCWSTR wsz) { LPSTR sz = NULL; DWORD cb = 0; assert(wsz != NULL); if(wsz == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } if( (cb = WideCharToMultiByte(0, 0, wsz, -1, NULL, 0, NULL, NULL)) == 0 || (sz = (char *) MyCoTaskMemAlloc(cb)) == NULL || (cb = WideCharToMultiByte(0, 0, wsz, -1, sz, cb, NULL, NULL)) == 0 ) { if(GetLastError() == ERROR_SUCCESS) SetLastError(ERROR_OUTOFMEMORY); return(NULL); } return(sz); } static LPWSTR WideFromMB(LPCSTR sz) { DWORD cch = 0; LPWSTR wsz = NULL; assert(sz != NULL); if(sz == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } if( (cch = MultiByteToWideChar(0, 0, sz, -1, NULL, 0)) == 0 || (wsz = (WCHAR *) MyCoTaskMemAlloc(cch * sizeof(WCHAR))) == NULL || (cch = MultiByteToWideChar(0, 0, sz, -1, wsz, cch)) == 0) { if(GetLastError() == ERROR_SUCCESS) SetLastError(ERROR_OUTOFMEMORY); return(NULL); } return(wsz); } static BSTR BSTRFromMB(LPCSTR sz) { BSTR bstr = NULL; DWORD cch = 0; WCHAR *pwsz = NULL; BOOL fFail = FALSE; assert(sz != NULL); if(sz == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } while (TRUE) { if(0 == (cch = MultiByteToWideChar(0, 0, sz, -1, pwsz, cch))) { //error fFail = TRUE; break; } if (NULL != pwsz) { //done break; } pwsz = (WCHAR *)LocalAlloc(LMEM_FIXED, cch * sizeof(WCHAR)); if (NULL == pwsz) { //error if(GetLastError() == ERROR_SUCCESS) SetLastError(ERROR_OUTOFMEMORY); break; } } if (!fFail && NULL != pwsz) { bstr = SysAllocString(pwsz); if (NULL == bstr) { if(GetLastError() == ERROR_SUCCESS) SetLastError(ERROR_OUTOFMEMORY); } } if (NULL != pwsz) { LocalFree(pwsz); } return(bstr); } static LPWSTR CopyWideString(LPCWSTR wsz) { size_t cch = 0; LPWSTR wszOut = NULL; // shouldn't send in a NULL assert(wsz != NULL); if(wsz == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } cch = wcslen(wsz) + 1; if (cch*sizeof(WCHAR) > (ULONG)-1) { // prevent errors caused by conversion from size_t --> ULONG SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } if( (wszOut = (LPWSTR) MyCoTaskMemAlloc((ULONG)(sizeof(WCHAR) * cch))) == NULL ) { SetLastError(ERROR_OUTOFMEMORY); return(NULL); } wcscpy(wszOut, wsz); return(wszOut); } static LPSTR CopyAsciiString(LPCSTR sz) { size_t cch = 0; LPSTR szOut = NULL; // shouldn't send in a NULL assert(sz != NULL); if(sz == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } cch = strlen(sz) + 1; if (cch > (ULONG)-1) { // prevent errors caused by conversion from size_t --> ULONG SetLastError(ERROR_INVALID_PARAMETER); return(NULL); } if( (szOut = (LPSTR) MyCoTaskMemAlloc((ULONG)cch)) == NULL ) { SetLastError(ERROR_OUTOFMEMORY); return(NULL); } strcpy(szOut, sz); return(szOut); } static DWORD KeyLocationFromStoreLocation(DWORD dwStoreFlags) { if( ((CERT_SYSTEM_STORE_LOCATION_MASK & dwStoreFlags) == CERT_SYSTEM_STORE_CURRENT_USER) || ((CERT_SYSTEM_STORE_LOCATION_MASK & dwStoreFlags) == CERT_SYSTEM_STORE_USERS) || ((CERT_SYSTEM_STORE_LOCATION_MASK & dwStoreFlags) == CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY) ) { return(0); } // CERT_SYSTEM_STORE_LOCAL_MACHINE // CERT_SYSTEM_STORE_DOMAIN_POLICY // CERT_SYSTEM_STORE_CURRENT_SERVICE // CERT_SYSTEM_STORE_SERVICES // CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY return(CRYPT_MACHINE_KEYSET); } //modified from myLoadRCString from ca HRESULT xeLoadRCString( IN HINSTANCE hInstance, IN int iRCId, OUT WCHAR **ppwsz) { #define REALLOCATEBLOCK 512 HRESULT hr; WCHAR *pwszTemp = NULL; int sizeTemp; int size = 0; int cBlocks = 1; *ppwsz = NULL; while (NULL == pwszTemp) { sizeTemp = cBlocks * REALLOCATEBLOCK; pwszTemp = (WCHAR*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeTemp * sizeof(WCHAR)); if (NULL == pwszTemp) { hr = E_OUTOFMEMORY; goto LocalAllocError; } size = LoadStringU( hInstance, iRCId, pwszTemp, sizeTemp); if (0 == size) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto LoadStringError; } if (size < sizeTemp - 1) { // ok, size is big enough break; } ++cBlocks; LocalFree(pwszTemp); pwszTemp = NULL; } *ppwsz = (WCHAR*) LocalAlloc(LPTR, (size+1) * sizeof(WCHAR)); if (NULL == *ppwsz) { hr = E_OUTOFMEMORY; goto LocalAllocError; } // copy it wcscpy(*ppwsz, pwszTemp); hr = S_OK; ErrorReturn: if (NULL != pwszTemp) { LocalFree(pwszTemp); } return hr; TRACE_ERROR(LocalAllocError) TRACE_ERROR(LoadStringError) } HANDLE CCEnroll::CreateOpenFileSafely2( LPCWSTR pwszFileName, DWORD idsCreate, DWORD idsOverwrite) { HANDLE hFile = NULL; WCHAR *pwszMsg = NULL; WCHAR *pwszFormat = NULL; WCHAR *pwszTitle = NULL; WCHAR *pwszSafety = NULL; DWORD dwAttribs = 0; BOOL fNotProperFile; LPCWSTR apwszInsertArray[2]; BOOL fNo; BOOL fMsgBox; int idPrefix = IDS_NOTSAFE_WRITE_PREFIX; //default to write prefix BOOL fCreate = (0xFFFFFFFF != idsCreate) && (0xFFFFFFFF != idsOverwrite); HRESULT hr; EnterCriticalSection(&m_csXEnroll); fMsgBox = (m_dwEnabledSafteyOptions != 0); dwAttribs = GetFileAttributesU(pwszFileName); if(0xFFFFFFFF == dwAttribs) { //file doesn't exist if (!fCreate) { //try to read a non-existing file //for safety reasons, don't return system error SetLastError(ERROR_ACCESS_DENIED); goto InvalidFileError; } //if got here, write a new file if (fMsgBox) { hr = xeLoadRCString(hInstanceXEnroll, idsCreate, &pwszFormat); if (S_OK != hr) { goto xeLoadRCStringError; } } } else { //file exists, check if a proper file to write or read //in either write or read, the following file attrib not proper fNotProperFile = (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) || (dwAttribs & FILE_ATTRIBUTE_HIDDEN) || (dwAttribs & FILE_ATTRIBUTE_SYSTEM); if (!fNotProperFile) { //so far so good if (fCreate) { //write a file if (0x0 != (dwAttribs & FILE_ATTRIBUTE_READONLY)) { //don't take read-only and archive fNotProperFile = TRUE; } else { //try to overwrite existing file hr = xeLoadRCString(hInstanceXEnroll, idsOverwrite, &pwszFormat); if (S_OK != hr) { goto xeLoadRCStringError; } //enforce popup if overwrite fMsgBox = TRUE; } } else { //read an existing file always violate scripting safety //it allows detecting file existence //put out a warning fMsgBox = TRUE; hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_OPEN, &pwszFormat); if (S_OK != hr) { goto xeLoadRCStringError; } idPrefix = IDS_NOTSAFE_OPEN_PREFIX; } } if (fNotProperFile) { //for safety reasons, don't return system error SetLastError(ERROR_ACCESS_DENIED); goto InvalidFileError; } } if (fMsgBox) { hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle); if (S_OK != hr) { goto xeLoadRCStringError; } hr = xeLoadRCString(hInstanceXEnroll, idPrefix, &pwszSafety); if (S_OK != hr) { goto xeLoadRCStringError; } apwszInsertArray[0] = pwszSafety; apwszInsertArray[1] = pwszFileName; if (!FormatMessageU( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, pwszFormat, 0, 0, (LPWSTR) &pwszMsg, 0, (va_list *)apwszInsertArray)) { goto FormatMessageError; } fNo = (MessageBoxU( NULL, pwszMsg, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES); if(fNo) { SetLastError(ERROR_CANCELLED); goto CancelError; } } hFile = CreateFileU( pwszFileName, fCreate ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, NULL, fCreate ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) { //don't return system error so keep xenroll relative safe for scripting SetLastError(ERROR_ACCESS_DENIED); hFile = NULL; goto CreateFileUError; } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); if(NULL != pwszMsg) { LocalFree(pwszMsg); } if(NULL != pwszFormat) { LocalFree(pwszFormat); } if(NULL != pwszTitle) { LocalFree(pwszTitle); } if(NULL != pwszSafety) { LocalFree(pwszSafety); } return(hFile); TRACE_ERROR(CreateFileUError) TRACE_ERROR(FormatMessageError); TRACE_ERROR(CancelError) TRACE_ERROR(InvalidFileError) TRACE_ERROR(xeLoadRCStringError) } HANDLE CCEnroll::CreateOpenFileSafely( LPCWSTR pwszFileName, BOOL fCreate) { HANDLE hFile = NULL; WCHAR *pwszMsg = NULL; DWORD dwAttribs = 0; BOOL fNotProperFile; WCHAR *pwszFormat = NULL; WCHAR *pwszTitle = NULL; LPCWSTR apwszInsertArray[] = {pwszFileName}; BOOL fNo; BOOL fMsgBox = 0 != m_dwEnabledSafteyOptions; BOOL fOverWrite = FALSE; HRESULT hr; EnterCriticalSection(&m_csXEnroll); dwAttribs = GetFileAttributesU(pwszFileName); if(0xFFFFFFFF == dwAttribs) { //file doesn't exist if (!fCreate) { //try to read a non-existing file //for safety reasons, don't return system error SetLastError(ERROR_ACCESS_DENIED); goto InvalidFileError; } } else { //file exists, check if a proper file to write or read //in either write or read, the following file attrib not proper fNotProperFile = (dwAttribs & FILE_ATTRIBUTE_DIRECTORY) || (dwAttribs & FILE_ATTRIBUTE_HIDDEN) || (dwAttribs & FILE_ATTRIBUTE_SYSTEM); if (!fNotProperFile) { //so far so good if (fCreate) { //write a file if (0x0 != (dwAttribs & FILE_ATTRIBUTE_READONLY)) { //don't take read-only and archive fNotProperFile = TRUE; } else { //try to overwrite existing file fOverWrite = TRUE; } } } if (fNotProperFile) { //for safety reasons, don't return system error SetLastError(ERROR_ACCESS_DENIED); goto InvalidFileError; } } if (fMsgBox) { hr = xeLoadRCString(hInstanceXEnroll, IDS_CERTENROLL, &pwszTitle); if (S_OK != hr) { goto xeLoadRCStringError; } hr = xeLoadRCString( hInstanceXEnroll, fCreate ? IDS_NOTSAFE_WRITE_FORMAT : IDS_NOTSAFE_OPEN_FORMAT, &pwszFormat); if (S_OK != hr) { goto xeLoadRCStringError; } if (!FormatMessageU( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, pwszFormat, 0, 0, (LPWSTR) &pwszMsg, 0, (va_list *)apwszInsertArray)) { goto FormatMessageUError; } fNo = (MessageBoxU( NULL, pwszMsg, pwszTitle, MB_DEFBUTTON2 | MB_YESNO | MB_ICONWARNING) == IDNO); if(fNo) { SetLastError(ERROR_CANCELLED); goto CancelError; } } if (fCreate && fOverWrite) { if (!fMsgBox) { hr = xeLoadRCString(hInstanceXEnroll, IDS_CERTENROLL, &pwszTitle); if (S_OK != hr) { goto xeLoadRCStringError; } } //popup overwrite confirmation hr = xeLoadRCString(hInstanceXEnroll, IDS_OVERWRITE_FORMAT, &pwszFormat); if (S_OK != hr) { goto xeLoadRCStringError; } //make sure free before alloc again if (NULL != pwszMsg) { LocalFree(pwszMsg); pwszMsg = NULL; } FormatMessageU( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY, pwszFormat, 0, 0, (LPWSTR) &pwszMsg, 0, (va_list *)apwszInsertArray); fNo = (MessageBoxU( NULL, pwszMsg, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2) != IDYES); if(fNo) { SetLastError(ERROR_CANCELLED); goto CancelError; } } hFile = CreateFileU( pwszFileName, fCreate ? GENERIC_WRITE : GENERIC_READ, FILE_SHARE_READ, NULL, fCreate ? CREATE_ALWAYS : OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hFile == INVALID_HANDLE_VALUE || hFile == NULL) { //don't return system error so keep xenroll relative safe for scripting SetLastError(ERROR_ACCESS_DENIED); hFile = NULL; goto CreateFileUError; } ErrorReturn: if(NULL != pwszMsg) { LocalFree(pwszMsg); } if(NULL != pwszTitle) { LocalFree(pwszTitle); } if(NULL != pwszFormat) { LocalFree(pwszFormat); } LeaveCriticalSection(&m_csXEnroll); return(hFile); TRACE_ERROR(CreateFileUError) TRACE_ERROR(CancelError) TRACE_ERROR(FormatMessageUError); TRACE_ERROR(InvalidFileError) TRACE_ERROR(xeLoadRCStringError) } HANDLE CCEnroll::CreateFileSafely( LPCWSTR pwszFileName) { return CreateOpenFileSafely(pwszFileName, TRUE); //write } HANDLE CCEnroll::OpenFileSafely( LPCWSTR pwszFileName) { return CreateOpenFileSafely(pwszFileName, FALSE); //open } void DwordToWide(DWORD dw, LPWSTR lpwstr) { DWORD i = 0; DWORD j; WCHAR wch; while(dw > 0) { j = dw % 10; dw /= 10; lpwstr[i++] = (WCHAR) (j + L'\0'); } if( i == 0 ) lpwstr[i++] = L'\0'; lpwstr[i] = 0; for(j=0, i--; i > j; i--, j++) { wch = lpwstr[i]; lpwstr[i] = lpwstr[j]; lpwstr[j] = wch; } } //take a name value pair info and return encoded value HRESULT xeEncodeNameValuePair( IN PCRYPT_ENROLLMENT_NAME_VALUE_PAIR pNameValuePair, OUT BYTE **ppbData, OUT DWORD *pcbData) { HRESULT hr = S_OK; //init *ppbData = NULL; *pcbData = 0; while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, szOID_ENROLLMENT_NAME_VALUE_PAIR, pNameValuePair, *ppbData, pcbData)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto error; } if (NULL != *ppbData) { break; } *ppbData = (BYTE*)MyCoTaskMemAlloc(*pcbData); if (NULL == *ppbData) { hr = E_OUTOFMEMORY; goto error; } } error: if (S_OK != hr && NULL != *ppbData) { MyCoTaskMemFree(*ppbData); *ppbData = NULL; } return hr; } //convert wsz to sz and allocate mem HRESULT xeWSZToSZ( IN LPCWSTR pwsz, OUT LPSTR *ppsz) { HRESULT hr = S_OK; LONG cc = 0; //init *ppsz = NULL; while (TRUE) { cc = WideCharToMultiByte( GetACP(), 0, pwsz, -1, *ppsz, cc, NULL, NULL); if (0 >= cc) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto error; } if (NULL != *ppsz) { break; } *ppsz= (CHAR*)MyCoTaskMemAlloc(cc); if (NULL == *ppsz) { hr = E_OUTOFMEMORY; goto error; } } error: if (S_OK != hr && NULL != *ppsz) { MyCoTaskMemFree(*ppsz); *ppsz = NULL; } return hr; } //modified from DecodeFile on certsrv HRESULT CCEnroll::xeStringToBinaryFromFile( IN WCHAR const *pwszfn, OUT BYTE **ppbOut, OUT DWORD *pcbOut, IN DWORD Flags) { HANDLE hFile; HRESULT hr; CHAR *pchFile = NULL; BYTE *pbOut = NULL; DWORD cchFile; DWORD cbRead; DWORD cbOut = 0; hFile = OpenFileSafely(pwszfn); if (NULL == hFile) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto OpenFileSafelyError; } cchFile = GetFileSize(hFile, NULL); if ((DWORD) -1 == cchFile) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetFileSizeError; } pchFile = (CHAR *) LocalAlloc(LMEM_FIXED, cchFile); if (NULL == pchFile) { hr = E_OUTOFMEMORY; goto LocalAllocError; } if (!ReadFile(hFile, pchFile, cchFile, &cbRead, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ReadFileError; } assert(cbRead <= cchFile); if (cbRead != cchFile) { hr = MY_HRESULT_FROM_WIN32(ERROR_HANDLE_EOF); goto ReadFileError; } if (CRYPT_STRING_BINARY == Flags) { pbOut = (BYTE *) pchFile; cbOut = cchFile; pchFile = NULL; } else { // Decode file contents. while (TRUE) { if (!MyCryptStringToBinaryA( pchFile, cchFile, Flags, pbOut, &cbOut, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CyrptStringToBinaryError; } if (NULL != pbOut) { //done break; } pbOut = (BYTE*)LocalAlloc(LMEM_FIXED, cbOut); if (NULL == pbOut) { hr = E_OUTOFMEMORY; goto LocalAllocError; } } } *pcbOut = cbOut; *ppbOut = pbOut; pbOut = NULL; hr = S_OK; error: if (INVALID_HANDLE_VALUE != hFile) { CloseHandle(hFile); } if (NULL != pchFile) { LocalFree(pchFile); } if (NULL != pbOut) { LocalFree(pbOut); } return(hr); ErrorReturn: goto error; TRACE_ERROR(CyrptStringToBinaryError) TRACE_ERROR(ReadFileError) TRACE_ERROR(LocalAllocError) TRACE_ERROR(GetFileSizeError) TRACE_ERROR(OpenFileSafelyError) } //following two functions handle some APIs not available //in downlevel client crypt32.dll typedef VOID (WINAPI * PFNCertFreeCertificateChain) (IN PCCERT_CHAIN_CONTEXT pChainContext); typedef BOOL (WINAPI * PFNCertGetCertificateChain) (IN OPTIONAL HCERTCHAINENGINE hChainEngine, IN PCCERT_CONTEXT pCertContext, IN OPTIONAL LPFILETIME pTime, IN OPTIONAL HCERTSTORE hAdditionalStore, IN PCERT_CHAIN_PARA pChainPara, IN DWORD dwFlags, IN LPVOID pvReserved, OUT PCCERT_CHAIN_CONTEXT* ppChainContext); typedef BOOL (WINAPI *PFNCertVerifyCertificateChainPolicy) ( LPCSTR pszPolicyOID, PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, PCERT_CHAIN_POLICY_STATUS pPolicyStatus ); typedef BOOL (*PFNCheckTokenMembership) ( HANDLE TokenHandle, // handle to access token PSID SidToCheck, // SID PBOOL IsMember // result ); typedef BOOL (*PFNSetSecurityDescriptorControl) ( PSECURITY_DESCRIPTOR pSecurityDescriptor, // SD SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, // control bits SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet // new control bits ); VOID MyCertFreeCertificateChain ( IN PCCERT_CHAIN_CONTEXT pChainContext ) { PFNCertFreeCertificateChain pfnCertFreeCertificateChain = NULL; HMODULE hModule = NULL; hModule = GetModuleHandle("crypt32.dll"); if (NULL != hModule) { pfnCertFreeCertificateChain = (PFNCertFreeCertificateChain) GetProcAddress(hModule, "CertFreeCertificateChain"); if (NULL != pfnCertFreeCertificateChain) { pfnCertFreeCertificateChain(pChainContext); } } } BOOL MyCertGetCertificateChain ( IN OPTIONAL HCERTCHAINENGINE hChainEngine, IN PCCERT_CONTEXT pCertContext, IN OPTIONAL LPFILETIME pTime, IN OPTIONAL HCERTSTORE hAdditionalStore, IN PCERT_CHAIN_PARA pChainPara, IN DWORD dwFlags, IN LPVOID pvReserved, OUT PCCERT_CHAIN_CONTEXT* ppChainContext ) { PFNCertGetCertificateChain pfnCertGetCertificateChain = NULL; HMODULE hModule = NULL; hModule = GetModuleHandle("crypt32.dll"); if (NULL != hModule) { pfnCertGetCertificateChain = (PFNCertGetCertificateChain) GetProcAddress(hModule, "CertGetCertificateChain"); if (NULL != pfnCertGetCertificateChain) { return pfnCertGetCertificateChain( hChainEngine, pCertContext, pTime, hAdditionalStore, pChainPara, dwFlags, pvReserved, ppChainContext); } } return FALSE; } BOOL MyCertVerifyCertificateChainPolicy( LPCSTR pszPolicyOID, PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara, PCERT_CHAIN_POLICY_STATUS pPolicyStatus ) { PFNCertVerifyCertificateChainPolicy pfnCertVerifyCertificateChainPolicy = NULL; HMODULE hModule = NULL; hModule = GetModuleHandle("crypt32.dll"); if (NULL != hModule) { pfnCertVerifyCertificateChainPolicy = (PFNCertVerifyCertificateChainPolicy) GetProcAddress(hModule, "CertVerifyCertificateChainPolicy"); if (NULL != pfnCertVerifyCertificateChainPolicy) { return pfnCertVerifyCertificateChainPolicy( pszPolicyOID, pChainContext, pPolicyPara, pPolicyStatus); } } return FALSE; } BOOL MyCheckTokenMembership( HANDLE TokenHandle, // handle to access token PSID SidToCheck, // SID PBOOL IsMember // result ) { PFNCheckTokenMembership pfnCheckTokenMembership = NULL; HMODULE hModule = NULL; hModule = GetModuleHandle("advapi32.dll"); if (NULL != hModule) { pfnCheckTokenMembership = (PFNCheckTokenMembership) GetProcAddress(hModule, "CheckTokenMembership"); if (NULL != pfnCheckTokenMembership) { return pfnCheckTokenMembership( TokenHandle, SidToCheck, IsMember); } } return FALSE; } BOOL MySetSecurityDescriptorControl( PSECURITY_DESCRIPTOR pSecurityDescriptor, // SD SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest, // control bits SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet // new control bits ) { PFNSetSecurityDescriptorControl pfnSetSecurityDescriptorControl = NULL; HMODULE hModule = NULL; hModule = GetModuleHandle("advapi32.dll"); if (NULL != hModule) { pfnSetSecurityDescriptorControl = (PFNSetSecurityDescriptorControl) GetProcAddress(hModule, "SetSecurityDescriptorControl"); if (NULL != pfnSetSecurityDescriptorControl) { return pfnSetSecurityDescriptorControl( pSecurityDescriptor, ControlBitsOfInterest, ControlBitsToSet); } } return FALSE; } HRESULT __stdcall CCEnroll::GetInterfaceSafetyOptions( /* [in] */ REFIID riid, /* [out] */ DWORD __RPC_FAR *pdwSupportedOptions, /* [out] */ DWORD __RPC_FAR *pdwEnabledOptions) { RPC_STATUS rpcStatus; if(0 != UuidCompare((GUID *) &riid, (GUID *) &IID_IDispatch, &rpcStatus) ) return(E_NOINTERFACE); *pdwEnabledOptions = m_dwEnabledSafteyOptions; *pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA; return(S_OK); } HRESULT __stdcall CCEnroll::SetInterfaceSafetyOptions( /* [in] */ REFIID riid, /* [in] */ DWORD dwOptionSetMask, /* [in] */ DWORD dwEnabledOptions) { RPC_STATUS rpcStatus; DWORD dwSupport = 0; if(0 != UuidCompare((GUID *) &riid, (GUID *) &IID_IDispatch, &rpcStatus) ) return(E_NOINTERFACE); dwSupport = dwOptionSetMask & ~(INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA); if(dwSupport != 0) return(E_FAIL); (DWORD)m_dwEnabledSafteyOptions &= ~dwOptionSetMask; (DWORD)m_dwEnabledSafteyOptions |= dwEnabledOptions; return(S_OK); } HRESULT CCEnroll::GetVerifyProv() { HRESULT hr; EnterCriticalSection(&m_csXEnroll); if (NULL == m_hVerifyProv) { if (!CryptAcquireContextU( &m_hVerifyProv, NULL, m_keyProvInfo.pwszProvName, m_keyProvInfo.dwProvType, CRYPT_VERIFYCONTEXT)) { #if DBG assert(NULL == m_hVerifyProv); #endif //DBG hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptAcquireContextUError; } } hr = S_OK; ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return hr; TRACE_ERROR(CryptAcquireContextUError) } BOOL CCEnroll::GetCapiHashAndSigAlgId(ALG_ID rgAlg[2]) { DWORD iHashBest = 0; ALG_ID arDefaultHash[] = {m_HashAlgId, CALG_SHA1, CALG_MD5}; DWORD cDefaultHash = sizeof(arDefaultHash) / sizeof(DWORD); HCRYPTPROV hProvU = NULL; DWORD dwFlags = CRYPT_FIRST; DWORD i; PROV_ENUMALGS enumAlgs; DWORD cb = sizeof(enumAlgs); BOOL fRet = TRUE; rgAlg[0] = 0; rgAlg[1] = 0; EnterCriticalSection(&m_csXEnroll); // only get a prov if one wasn't passed in. if(m_hProv == NULL) { HRESULT hr; hr = GetVerifyProv(); if (S_OK != hr) { goto GetVerifyProvError; } hProvU = m_hVerifyProv; } else { // otherwise use the current m_hProv, SCard only likes on // CryptAcquireContext to be used. hProvU = m_hProv; } cb = sizeof(enumAlgs); while( CryptGetProvParam( hProvU, PP_ENUMALGS, (BYTE *) &enumAlgs, &cb, dwFlags ) ) { cb = sizeof(enumAlgs); // not first pass anymore dwFlags = 0; // see if this is a hash alg if( ALG_CLASS_HASH == GET_ALG_CLASS(enumAlgs.aiAlgid) ) { // get things init with the first hash alg if(rgAlg[0] == 0) { rgAlg[0] = enumAlgs.aiAlgid; iHashBest = cDefaultHash; } // pick the best one for(i=0; idwKeySpec, wszKeySpec); DwordToWide(pKeyProvInfo->dwProvType, wszProvType); // get total length of string cbContainer = (DWORD)(wcslen(pKeyProvInfo->pwszContainerName) + 1) * sizeof(WCHAR); cbKeySpec = (DWORD)(wcslen(wszKeySpec) + 1) * sizeof(WCHAR); cbProvType = (DWORD)(wcslen(wszProvType) + 1) * sizeof(WCHAR); cbProvName = (DWORD)(wcslen(pKeyProvInfo->pwszProvName) + 1) * sizeof(WCHAR); pBlob->cbData = cbContainer + cbKeySpec + cbProvType + cbProvName + sizeof(WCHAR); // allocate the string if( (pBlob->pbData = (BYTE *) MyCoTaskMemAlloc(pBlob->cbData)) == NULL) { SetLastError(ERROR_OUTOFMEMORY); return(FALSE); } // copy the strings memset(pBlob->pbData, 0, pBlob->cbData); memcpy(pBlob->pbData, pKeyProvInfo->pwszContainerName, cbContainer); memcpy(&pBlob->pbData[cbContainer], wszKeySpec, cbKeySpec); memcpy(&pBlob->pbData[cbContainer + cbKeySpec], wszProvType, cbProvType); memcpy(&pBlob->pbData[cbContainer + cbKeySpec + cbProvType], pKeyProvInfo->pwszProvName, cbProvName); return(TRUE); } static LPWSTR wszEmpty = L""; static LPWSTR wszMY = L"MY"; static LPWSTR wszCA = L"CA"; static LPWSTR wszROOT = L"ROOT"; static LPWSTR wszREQUEST = L"REQUEST"; static LPSTR szSystemStore = sz_CERT_STORE_PROV_SYSTEM; // static LPSTR szSystemStore = sz_CERT_STORE_PROV_SYSTEM_REGISTRY; ///////////////////////////////////////////////////////////////////////////// // CCEnroll CCEnroll::~CCEnroll(void) { Destruct(); DeleteCriticalSection(&m_csXEnroll); } void CCEnroll::Destruct(void) { if(NULL != m_PrivateKeyArchiveCertificate) { CertFreeCertificateContext(m_PrivateKeyArchiveCertificate); } if(NULL != m_pCertContextSigner) { CertFreeCertificateContext(m_pCertContextSigner); } if(m_pCertContextRenewal != NULL) CertFreeCertificateContext(m_pCertContextRenewal); if(m_pCertContextStatic != NULL) CertFreeCertificateContext(m_pCertContextStatic); if(m_keyProvInfo.pwszContainerName != wszEmpty) MyCoTaskMemFree(m_keyProvInfo.pwszContainerName); if(m_keyProvInfo.pwszProvName != wszEmpty) MyCoTaskMemFree(m_keyProvInfo.pwszProvName); if(m_MyStore.wszName != wszMY) MyCoTaskMemFree(m_MyStore.wszName); if(m_CAStore.wszName != wszCA) MyCoTaskMemFree(m_CAStore.wszName); if(m_RootStore.wszName != wszROOT && m_RootStore.wszName != wszCA) MyCoTaskMemFree(m_RootStore.wszName); if(m_RequestStore.wszName != wszREQUEST) MyCoTaskMemFree(m_RequestStore.wszName); if(m_MyStore.szType != szSystemStore) MyCoTaskMemFree(m_MyStore.szType); if(m_CAStore.szType != szSystemStore) MyCoTaskMemFree(m_CAStore.szType); if(m_RootStore.szType != szSystemStore) MyCoTaskMemFree(m_RootStore.szType); if(m_RequestStore.szType != szSystemStore) MyCoTaskMemFree(m_RequestStore.szType); if(m_wszSPCFileName != wszEmpty) MyCoTaskMemFree(m_wszSPCFileName); if(m_wszPVKFileName != wszEmpty) MyCoTaskMemFree(m_wszPVKFileName); if (NULL != m_pCertContextPendingRequest) CertFreeCertificateContext(m_pCertContextPendingRequest); if (NULL != m_pPendingRequestTable) delete m_pPendingRequestTable; // store handles if(m_RootStore.hStore != NULL) CertCloseStore(m_RootStore.hStore, 0); m_RootStore.hStore = NULL; if(m_CAStore.hStore != NULL) CertCloseStore(m_CAStore.hStore, 0); m_CAStore.hStore = NULL; if(m_MyStore.hStore != NULL) CertCloseStore(m_MyStore.hStore, 0); m_MyStore.hStore = NULL; if(m_RequestStore.hStore != NULL) CertCloseStore(m_RequestStore.hStore, 0); m_RequestStore.hStore = NULL; // remove provider handles if(m_hProv != NULL) CryptReleaseContext(m_hProv, 0); m_hProv = NULL; if(m_hVerifyProv != NULL) CryptReleaseContext(m_hVerifyProv, 0); m_hVerifyProv = NULL; if (NULL != m_hCachedKey) { //this should be destroyed early but just in case CryptDestroyKey(m_hCachedKey); } if (NULL != m_pPublicKeyInfo) { LocalFree(m_pPublicKeyInfo); m_pPublicKeyInfo = NULL; } FreeAllStackExtension(); FreeAllStackAttribute(); resetBlobProperties(); } static LPVOID CoTaskMemAllocTrap(ULONG cb) { __try { return(CoTaskMemAlloc(cb)); } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_DLL_NOT_FOUND); return(NULL); } } static LPVOID CoTaskMemReallocTrap(LPVOID ptr, ULONG cb) { __try { return(CoTaskMemRealloc(ptr, cb)); } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_DLL_NOT_FOUND); return(NULL); } } static void CoTaskMemFreeTrap(LPVOID ptr) { __try { CoTaskMemFree(ptr); } __except(EXCEPTION_EXECUTE_HANDLER) { SetLastError(ERROR_DLL_NOT_FOUND); } return; } // Initialize the safety options in the constructor, so they won't // be clobbered when we do a reset(). CCEnroll::CCEnroll(void) : m_dwEnabledSafteyOptions(0) { __try { InitializeCriticalSection(&m_csXEnroll); } __except(EXCEPTION_EXECUTE_HANDLER) { } Init(); } HRESULT CCEnroll::Init(void) { HRESULT hr; GUID guidContainerName; char * sz = NULL; RPC_STATUS rpc_status; // set default mem allocators if(MyCoTaskMemAlloc == NULL) { MyCoTaskMemAlloc = CoTaskMemAllocTrap; MyCoTaskMemRealloc = CoTaskMemReallocTrap; MyCoTaskMemFree = CoTaskMemFreeTrap; } // get a container based on a guid rpc_status = UuidCreate(&guidContainerName); if (RPC_S_OK != rpc_status && RPC_S_UUID_LOCAL_ONLY != rpc_status) { hr = rpc_status; goto UuidCreateError; } rpc_status = UuidToStringA(&guidContainerName, (unsigned char **) &sz); if (RPC_S_OK != rpc_status) { hr = rpc_status; goto UuidToStringAError; } assert(sz != NULL); m_keyProvInfo.pwszContainerName = WideFromMB(sz); RpcStringFree((unsigned char **) &sz); m_keyProvInfo.pwszProvName = wszEmpty; m_keyProvInfo.dwProvType = PROV_RSA_FULL; m_keyProvInfo.dwFlags = 0; m_keyProvInfo.cProvParam = 0; m_keyProvInfo.rgProvParam = NULL; m_keyProvInfo.dwKeySpec = AT_SIGNATURE; m_fEnableSMIMECapabilities = (m_keyProvInfo.dwKeySpec == AT_KEYEXCHANGE); m_fSMIMESetByClient = FALSE; m_fKeySpecSetByClient = FALSE; m_hProv = NULL; m_hVerifyProv = NULL; m_fDeleteRequestCert = TRUE; m_fUseExistingKey = FALSE; m_fWriteCertToCSPModified = FALSE; m_fWriteCertToCSP = TRUE; // always want to try m_fWriteCertToUserDSModified = FALSE; m_fWriteCertToUserDS = FALSE; m_fReuseHardwareKeyIfUnableToGenNew = TRUE; m_fLimitExchangeKeyToEncipherment = FALSE; m_dwT61DNEncoding = 0; // or CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG m_dwGenKeyFlags = 0; m_wszSPCFileName = wszEmpty; m_wszPVKFileName = wszEmpty; m_HashAlgId = 0; m_fMyStoreOpenFlagsModified = FALSE; m_MyStore.wszName = wszMY; m_MyStore.szType = szSystemStore; m_MyStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER; m_MyStore.hStore = NULL; m_fCAStoreOpenFlagsModified = FALSE; m_CAStore.wszName = wszCA; m_CAStore.szType = szSystemStore; m_CAStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER; m_CAStore.hStore = NULL; m_fRootStoreOpenFlagsModified = FALSE; m_RootStore.wszName = wszROOT; m_RootStore.szType = szSystemStore; m_RootStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER; m_RootStore.hStore = NULL; m_fRequestStoreOpenFlagsModified = FALSE; m_RequestStore.wszName = wszREQUEST ; m_RequestStore.szType = szSystemStore; m_RequestStore.dwFlags = CERT_SYSTEM_STORE_CURRENT_USER; m_RequestStore.hStore = NULL; m_PrivateKeyArchiveCertificate= NULL; m_pCertContextRenewal = NULL; m_pCertContextSigner = NULL; m_pCertContextStatic = NULL; memset(m_arHashBytesNewCert, 0, sizeof(m_arHashBytesNewCert)); memset(m_arHashBytesOldCert, 0, sizeof(m_arHashBytesOldCert)); m_fArchiveOldCert = FALSE; m_pExtStack = NULL; m_cExtStack = 0; m_pAttrStack = NULL; m_cAttrStack = 0; m_pExtStackNew = NULL; m_cExtStackNew = 0; m_pAttrStackNew = NULL; m_cAttrStackNew = 0; m_pPropStack = NULL; m_cPropStack = 0; m_fNewRequestMethod = FALSE; m_fCMCFormat = FALSE; m_fHonorRenew = TRUE; //critical, if passing XECR_PKCS10* m_fOID_V2 = FALSE; //critical m_hCachedKey = NULL; m_fUseClientKeyUsage = FALSE; m_lClientId = XECI_XENROLL; m_dwLastAlgIndex = MAXDWORD; m_fIncludeSubjectKeyID = TRUE; m_fHonorIncludeSubjectKeyID = FALSE; m_pPublicKeyInfo = NULL; m_dwSigKeyLenMax = 0; m_dwSigKeyLenMin = 0; m_dwSigKeyLenDef = 0; m_dwSigKeyLenInc = 0; m_dwXhgKeyLenMax = 0; m_dwXhgKeyLenMin = 0; m_dwXhgKeyLenDef = 0; m_dwXhgKeyLenInc = 0; // Initialize pending info data: m_pCertContextPendingRequest = NULL; m_pCertContextLastEnumerated = NULL; m_dwCurrentPendingRequestIndex = 0; m_pPendingRequestTable = NULL; memset(&m_hashBlobPendingRequest, 0, sizeof(CRYPT_DATA_BLOB)); ZeroMemory(&m_blobResponseKAHash, sizeof(m_blobResponseKAHash)); hr = S_OK; ErrorReturn: return hr; TRACE_ERROR(UuidToStringAError) TRACE_ERROR(UuidCreateError) } void CCEnroll::FlushStore(StoreType storeType) { PSTOREINFO pStoreInfo = NULL; // get store struct switch(storeType) { case StoreMY: pStoreInfo = &m_MyStore; break; case StoreCA: pStoreInfo = &m_CAStore; break; case StoreROOT: pStoreInfo = &m_RootStore; break; case StoreREQUEST: pStoreInfo = &m_RequestStore; break; } EnterCriticalSection(&m_csXEnroll); // if store already open, return it if(pStoreInfo->hStore != NULL) { CertCloseStore(pStoreInfo->hStore, 0); pStoreInfo->hStore = NULL; } // we may have something or not, but return it // the errors will be correct. LeaveCriticalSection(&m_csXEnroll); } HCERTSTORE CCEnroll::GetStore(StoreType storeType) { PSTOREINFO pStoreInfo = NULL; HCERTSTORE hStore = NULL; // get store struct switch(storeType) { case StoreMY: pStoreInfo = &m_MyStore; break; case StoreCA: pStoreInfo = &m_CAStore; break; case StoreROOT: pStoreInfo = &m_RootStore; break; case StoreREQUEST: pStoreInfo = &m_RequestStore; break; default: SetLastError(ERROR_BAD_ARGUMENTS); return(NULL); break; } EnterCriticalSection(&m_csXEnroll); // if store already open, return it if(pStoreInfo->hStore == NULL) { // otherwise attempt to open the store pStoreInfo->hStore = CertOpenStore( pStoreInfo->szType, PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, NULL, pStoreInfo->dwFlags, pStoreInfo->wszName); } // we may have something or not, but return it // the errors will be correct. hStore = pStoreInfo->hStore; LeaveCriticalSection(&m_csXEnroll); return(hStore); } HCRYPTPROV CCEnroll::GetProv(DWORD dwFlags) { HCRYPTPROV hProvT = NULL; DWORD cb = 0; char * pszProvName = NULL; char * pszContainerName = NULL; EnterCriticalSection(&m_csXEnroll); DWORD dwProvType = m_keyProvInfo.dwProvType; switch(dwFlags) { case CRYPT_NEWKEYSET: dwFlags = dwFlags | m_keyProvInfo.dwFlags; break; case CRYPT_DELETEKEYSET: if( m_hProv != NULL ) { CryptReleaseContext(m_hProv, 0); m_hProv = NULL; CryptAcquireContextU(&m_hProv, m_keyProvInfo.pwszContainerName, m_keyProvInfo.pwszProvName, m_keyProvInfo.dwProvType, CRYPT_DELETEKEYSET); } m_hProv = NULL; goto CommonReturn; break; default: dwFlags = m_keyProvInfo.dwFlags; break; } if(m_hProv == NULL) { if( CryptAcquireContextU(&m_hProv, m_keyProvInfo.pwszContainerName, m_keyProvInfo.pwszProvName, m_keyProvInfo.dwProvType, dwFlags) ) { // we have the m_hProv, now set the provider name // Since this is secondary to the task, don't do error checking // nothing here should really fail anyway pszProvName = NULL; while (TRUE) { if(!CryptGetProvParam( m_hProv, PP_NAME, (BYTE*)pszProvName, &cb, 0)) { break; } if (NULL != pszProvName) { if(m_keyProvInfo.pwszProvName != wszEmpty) MyCoTaskMemFree(m_keyProvInfo.pwszProvName); m_keyProvInfo.pwszProvName = WideFromMB(pszProvName); break; } pszProvName = (char *)LocalAlloc(LMEM_FIXED, cb); if (NULL == pszProvName) { goto CommonReturn; } } // Here we just try and get the unique container name // If not, just go on BOOL fTryAnother = FALSE; cb = 0; pszContainerName = NULL; while (TRUE) { if(!CryptGetProvParam( m_hProv, PP_UNIQUE_CONTAINER, (BYTE*)pszContainerName, &cb, 0)) { if (NULL == pszContainerName) { fTryAnother = TRUE; } else { LocalFree(pszContainerName); pszContainerName = NULL; } break; } else { if (NULL != pszContainerName) { //got it, done break; } } pszContainerName = (char *)LocalAlloc(LMEM_FIXED, cb); if (NULL == pszContainerName) { goto CommonReturn; } } if (fTryAnother) { // so we can't get the unique container name, // lets just go for the container name (may not be unique). cb = 0; pszContainerName = NULL; while (TRUE) { if(!CryptGetProvParam(m_hProv, PP_CONTAINER, (BYTE*)pszContainerName, &cb, 0)) { if (NULL != pszContainerName) { LocalFree(pszContainerName); pszContainerName = NULL; } break; } else { if (NULL != pszContainerName) { //got it, done break; } pszContainerName = (char *)LocalAlloc(LMEM_FIXED, cb); if (NULL == pszContainerName) { goto CommonReturn; } } } } // set the container, otherwise use what was there if(pszContainerName != NULL) { if( m_keyProvInfo.pwszContainerName != wszEmpty ) MyCoTaskMemFree(m_keyProvInfo.pwszContainerName); m_keyProvInfo.pwszContainerName = WideFromMB(pszContainerName); } // now because some providers double duty for provider types // get what the the provider thinks its type is cb = sizeof(DWORD); if(CryptGetProvParam( m_hProv, PP_PROVTYPE, (BYTE *) &dwProvType, &cb, 0) ) { m_keyProvInfo.dwProvType = dwProvType; } } else { m_hProv = NULL; } } CommonReturn: hProvT = m_hProv; LeaveCriticalSection(&m_csXEnroll); if (NULL != pszProvName) { LocalFree(pszProvName); } if (NULL != pszContainerName) { LocalFree(pszContainerName); } return(hProvT); } BOOL CCEnroll::SetKeyParams( PCRYPT_KEY_PROV_INFO pKeyProvInfo ) { EnterCriticalSection(&m_csXEnroll); // remove provider handles if(m_hProv != NULL) CryptReleaseContext(m_hProv, 0); m_hProv = NULL; if(m_hVerifyProv != NULL) CryptReleaseContext(m_hVerifyProv, 0); m_hVerifyProv = NULL; put_ContainerNameWStr(pKeyProvInfo->pwszContainerName); put_ProviderNameWStr(pKeyProvInfo->pwszProvName); put_ProviderFlags(pKeyProvInfo->dwFlags); put_KeySpec(pKeyProvInfo->dwKeySpec); put_ProviderType(pKeyProvInfo->dwProvType); // someday we will have to pay attention to this too. m_keyProvInfo.cProvParam = 0; m_keyProvInfo.rgProvParam = NULL; LeaveCriticalSection(&m_csXEnroll); return(TRUE); } HRESULT STDMETHODCALLTYPE CCEnroll::createPKCS10( /* [in] */ BSTR DNName, /* [in] */ BSTR wszPurpose, /* [retval][out] */ BSTR __RPC_FAR *pPKCS10) { return(createPKCS10WStrBStr(DNName, wszPurpose, pPKCS10)); } HRESULT CCEnroll::createPKCS10WStrBStr( LPCWSTR DNName, LPCWSTR wszPurpose, BSTR __RPC_FAR *pPKCS10) { HRESULT hr = S_OK; CRYPT_DATA_BLOB blobPKCS10; memset(&blobPKCS10, 0, sizeof(CRYPT_DATA_BLOB)); hr = createPKCS10WStr(DNName, wszPurpose, &blobPKCS10); if(S_OK != hr) { goto createPKCS10Error; } // BASE64 encode pkcs 10, no header for backward compatible hr = BlobToBstring(&blobPKCS10, CRYPT_STRING_BASE64, pPKCS10); if (S_OK != hr) { goto BlobToBstringError; } CommonReturn: if(NULL != blobPKCS10.pbData) { MyCoTaskMemFree(blobPKCS10.pbData); } return(hr); ErrorReturn: if(*pPKCS10 != NULL) SysFreeString(*pPKCS10); *pPKCS10 = NULL; goto CommonReturn; TRACE_ERROR(createPKCS10Error); TRACE_ERROR(BlobToBstringError); } HRESULT CCEnroll::AddCertsToStores( HCERTSTORE hStoreMsg, LONG *plCertInstalled ) { HCERTSTORE hStoreRoot = NULL; HCERTSTORE hStoreCA = NULL; PCCERT_CONTEXT pCertContext = NULL; PCCERT_CONTEXT pCertContextLast = NULL; LONG lCertInstalled = 0; HRESULT hr = S_OK; //init if (NULL != plCertInstalled) { *plCertInstalled = 0; } EnterCriticalSection(&m_csXEnroll); if( (hStoreCA = GetStore(StoreCA)) == NULL ) goto ErrorCertOpenCAStore; if( (hStoreRoot = GetStore(StoreROOT)) == NULL ) goto ErrorCertOpenRootStore; // now just place the rest of the cert in either the ROOT or CA store // we know we removed the end-entity cert from the msg store already // put all certs that came in the message into the appropriate store while( (pCertContext = CertEnumCertificatesInStore( hStoreMsg, pCertContextLast)) != NULL ) { // if it is a self sign, it is a ROOT if( CertCompareCertificateName( CRYPT_ASN_ENCODING, &pCertContext->pCertInfo->Subject, &pCertContext->pCertInfo->Issuer) ) { // to root store could invoke a pop up, check cancel button // but don't error out from any fail if (MySafeCertAddCertificateContextToStore( hStoreRoot, pCertContext, CERT_STORE_ADD_USE_EXISTING, NULL, m_dwEnabledSafteyOptions)) { ++lCertInstalled; } else { if (S_OK == hr) { //save the 1st error as return hr = MY_HRESULT_FROM_WIN32(GetLastError()); if (HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) == hr) { //map generic access deny to xenroll error hr = XENROLL_E_CANNOT_ADD_ROOT_CERT; } } //don't goto error here and finish the loop } } // if it is not the MY cert, it must go in the CA store // do nothing with the MY cert as we already handled it else { // likewise we don't care if these get added to the // CA store if (MySafeCertAddCertificateContextToStore( hStoreCA, pCertContext, CERT_STORE_ADD_USE_EXISTING, NULL, m_dwEnabledSafteyOptions)) { //no error code check ++lCertInstalled; } } pCertContextLast = pCertContext; } pCertContextLast = NULL; if (NULL != plCertInstalled) { *plCertInstalled = lCertInstalled; } CommonReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: hr = MY_HRESULT_FROM_WIN32(GetLastError()); if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); goto CommonReturn; TRACE_ERROR(ErrorCertOpenCAStore); TRACE_ERROR(ErrorCertOpenRootStore); } BOOL IsDesiredProperty(DWORD dwPropertyId) { DWORD DesiredIds[] = { CERT_PVK_FILE_PROP_ID, CERT_FRIENDLY_NAME_PROP_ID, CERT_DESCRIPTION_PROP_ID, CERT_RENEWAL_PROP_ID, }; DWORD i; for (i = 0; i < ARRAYSIZE(DesiredIds); ++i) { if (dwPropertyId == DesiredIds[i]) { return TRUE; } } return FALSE; } BOOL IsFilteredOutProperty(DWORD dwPropertyId) { DWORD FilteredIds[] = { XENROLL_RENEWAL_CERTIFICATE_PROP_ID, XENROLL_PASS_THRU_PROP_ID, CERT_KEY_PROV_INFO_PROP_ID, CERT_ENROLLMENT_PROP_ID, //pending property }; DWORD i; for (i = 0; i < ARRAYSIZE(FilteredIds); ++i) { if (dwPropertyId == FilteredIds[i]) { return TRUE; } } return FALSE; } HRESULT CCEnroll::GetEndEntityCert( PCRYPT_DATA_BLOB pBlobPKCS7, BOOL fSaveToStores, PCCERT_CONTEXT *ppCert ) { HRESULT hr = S_OK; HCERTSTORE hStoreMsg = NULL; HCERTSTORE hStoreMy = NULL; HCERTSTORE hStoreRequest = NULL; PCCERT_CONTEXT pCertContextLast = NULL; PCCERT_CONTEXT pCertContextRequest = NULL; PCCERT_CONTEXT pCertContextMsg = NULL; PCCERT_CONTEXT pCertContextArchive = NULL; PCRYPT_KEY_PROV_INFO pKeyProvInfo = NULL; DWORD cb = 0; CRYPT_DATA_BLOB blobData; CRYPT_HASH_BLOB blobHash = {sizeof(m_arHashBytesNewCert), m_arHashBytesNewCert}; CRYPT_HASH_BLOB blobHashRenew = {sizeof(m_arHashBytesOldCert), m_arHashBytesOldCert}; RequestFlags requestFlags; CRYPT_HASH_BLOB requestFlagsBlob; CRYPT_HASH_BLOB renewalCertBlob; //Bug #202557 for IE3.02 upd clients (xiaohs) HCRYPTPROV hProv=NULL; BOOL fSetting; DWORD dwPropertyId; CRYPT_DATA_BLOB blobProp; BYTE *pbArchivedKeyHash = NULL; DWORD cbArchivedKeyHash = 0; EnterCriticalSection(&m_csXEnroll); memset(&requestFlags, 0, sizeof(RequestFlags)); memset(&blobData, 0, sizeof(CRYPT_DATA_BLOB)); memset(&requestFlagsBlob, 0, sizeof(CRYPT_DATA_BLOB)); memset(&renewalCertBlob, 0, sizeof(CRYPT_DATA_BLOB)); ZeroMemory(&blobProp, sizeof(blobProp)); if (NULL == ppCert) { hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto InvalidParameterError; } //init return *ppCert = NULL; if(!MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB, pBlobPKCS7, (CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED) , CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, NULL, &hStoreMsg, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCryptQueryObject; } // check to see if this hash is in the message if (m_pCertContextStatic == NULL || (NULL == (pCertContextMsg = CertFindCertificateInStore( hStoreMsg, X509_ASN_ENCODING, 0, CERT_FIND_HASH, &blobHash, NULL)))) { // open the request store if (NULL == (hStoreRequest = GetStore(StoreREQUEST))) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertOpenRequestStore; } // find cert in request store that matches cert // in message, by public key while (NULL != (pCertContextMsg = CertEnumCertificatesInStore( hStoreMsg, pCertContextLast))) { // check to see if this is in the request store if (NULL != (pCertContextRequest = CertFindCertificateInStore( hStoreRequest, CRYPT_ASN_ENCODING, 0, CERT_FIND_PUBLIC_KEY, (void *) &pCertContextMsg->pCertInfo->SubjectPublicKeyInfo, NULL))) { // found a match, get out break; } pCertContextLast = pCertContextMsg; } pCertContextLast = NULL; // if we didn't find one, then GetLastError was set either // by CertEnumCerificatesInStore or CertEnumCerificatesInStore if (NULL == pCertContextRequest) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorNoCertFound; } if (fSaveToStores) { // check archived key hash property first // if the property exists, means key archival was in the request cb = 0; while (TRUE) { if(!CertGetCertificateContextProperty( pCertContextRequest, CERT_ARCHIVED_KEY_HASH_PROP_ID, pbArchivedKeyHash, &cbArchivedKeyHash)) { if (NULL == pbArchivedKeyHash) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); if (MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND) == hr) { //no such property, so we are done break; } // some other error goto ErrorCertGetCertificateContextProperty; } else { //if pbArchivedKeyHash non-null, error hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertGetCertificateContextProperty; } } if (NULL != pbArchivedKeyHash) { //got it, done break; } pbArchivedKeyHash = (BYTE*)LocalAlloc( LMEM_FIXED, cbArchivedKeyHash); if (NULL == pbArchivedKeyHash) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (NULL != pbArchivedKeyHash && NULL == m_blobResponseKAHash.pbData) { //request cert has archived key hash but response //doesn't contain key hash for verification. maybe //a spoofing response? hr = XENROLL_E_RESPONSE_KA_HASH_NOT_FOUND; goto ResponseKAHashNotFoundError; } if (NULL == pbArchivedKeyHash && NULL != m_blobResponseKAHash.pbData) { //request cert doesn't have archived key hash but //response does. confliciting. seems no security harm hr = XENROLL_E_RESPONSE_UNEXPECTED_KA_HASH; goto ResponseUnexpectedKAHashError; } if (NULL != pbArchivedKeyHash && NULL != m_blobResponseKAHash.pbData) { //now we should check if they match //compare size and hash if (cbArchivedKeyHash != m_blobResponseKAHash.cbData || 0 != memcmp(pbArchivedKeyHash, m_blobResponseKAHash.pbData, cbArchivedKeyHash)) { //oh, potential attack hr = XENROLL_E_RESPONSE_KA_HASH_MISMATCH; //should remove the request cert? goto ResponseKAMismatchError; } } } // get those request cert properties that are, // either the property not blob property // or blob property needs special handling // Important: remember to add these Ids in IsFilteredOutProperty fSetting = TRUE; cb = 0; while (TRUE) { if(!CertGetCertificateContextProperty( pCertContextRequest, CERT_KEY_PROV_INFO_PROP_ID, pKeyProvInfo, &cb)) { if (NULL == pKeyProvInfo) { //skip setting fSetting = FALSE; break; } else { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertGetCertificateContextProperty; } } if (NULL != pKeyProvInfo) { //got it, done break; } pKeyProvInfo = (PCRYPT_KEY_PROV_INFO)LocalAlloc(LMEM_FIXED, cb); if (NULL == pKeyProvInfo) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (fSetting) { // put the property on the returned cert if( !CertSetCertificateContextProperty( pCertContextMsg, CERT_KEY_PROV_INFO_PROP_ID, 0, pKeyProvInfo) ) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorSetMyCertPropError; } // Set the provider info SetKeyParams(pKeyProvInfo); } fSetting = TRUE; while (TRUE) { if(!CertGetCertificateContextProperty( pCertContextRequest, XENROLL_PASS_THRU_PROP_ID, requestFlagsBlob.pbData, &requestFlagsBlob.cbData) ) { if (NULL == requestFlagsBlob.pbData) { //do nothing fSetting = FALSE; break; } else { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorDecodeRequestFlags; } } if (NULL != requestFlagsBlob.pbData) { //got it, done break; } requestFlagsBlob.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, requestFlagsBlob.cbData); if (NULL == requestFlagsBlob.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (fSetting) { // get the encoded blob cb = sizeof(requestFlags); // since this is a private data structure, its size should be // known and this should aways pass if (!CryptDecodeObject( CRYPT_ASN_ENCODING, XENROLL_REQUEST_INFO, requestFlagsBlob.pbData, requestFlagsBlob.cbData, 0, &requestFlags, &cb)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorDecodeRequestFlags; } // now set the flags if(!m_fWriteCertToCSPModified) m_fWriteCertToCSP = requestFlags.fWriteToCSP; if(!m_fWriteCertToUserDSModified) m_fWriteCertToUserDS = requestFlags.fWriteToDS; if(!m_fRequestStoreOpenFlagsModified) m_RequestStore.dwFlags = requestFlags.openFlags; if(!m_fMyStoreOpenFlagsModified) m_MyStore.dwFlags = (m_MyStore.dwFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) | (requestFlags.openFlags & CERT_SYSTEM_STORE_LOCATION_MASK); if(!m_fCAStoreOpenFlagsModified) m_CAStore.dwFlags = (m_CAStore.dwFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) | (requestFlags.openFlags & CERT_SYSTEM_STORE_LOCATION_MASK); if(!m_fRootStoreOpenFlagsModified) { // // POTENTIAL SCRIPTING VIOLATION: we're mapping request store flags directly to root store flags. // If they have set request store flags to local machine, propagate this setting to the root store flags, // but set the root store name to "CA". // if (0 != m_dwEnabledSafteyOptions) { if (requestFlags.openFlags & CERT_SYSTEM_STORE_LOCAL_MACHINE) { m_RootStore.wszName = wszCA; } } m_RootStore.dwFlags = (m_RootStore.dwFlags & ~CERT_SYSTEM_STORE_LOCATION_MASK) | (requestFlags.openFlags & CERT_SYSTEM_STORE_LOCATION_MASK); } } // see if this is a renewal request m_fArchiveOldCert = FALSE; fSetting = TRUE; while (TRUE) { // get the encoded blob if (!CertGetCertificateContextProperty( pCertContextRequest, XENROLL_RENEWAL_CERTIFICATE_PROP_ID, renewalCertBlob.pbData, &renewalCertBlob.cbData)) { if (NULL == renewalCertBlob.pbData) { fSetting = FALSE; break; } else { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertGetCertificateContextProperty; } } if (NULL != renewalCertBlob.pbData) { //got it, done break; } renewalCertBlob.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, renewalCertBlob.cbData); if (NULL == renewalCertBlob.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (fSetting) { //Bug #202557 for IE3.02 upd clients (xiaohs) if (NULL==hProv) { if(!CryptAcquireContext( &hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorAcquireContext; } } if (!CryptHashCertificate( hProv, //NULL, Bug #202557 for IE3.02 upd clients (xiaohs) 0, //alg X509_ASN_ENCODING, //0 dwFlags renewalCertBlob.pbData, renewalCertBlob.cbData, blobHashRenew.pbData, &blobHashRenew.cbData)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCryptHashCertificate; } m_fArchiveOldCert = TRUE; } //get rest of blob properties from request store and set to the cert dwPropertyId = CertEnumCertificateContextProperties( pCertContextRequest, 0); //enum from 1st while (0 != dwPropertyId) { // if (!IsFilteredOutProperty(dwPropertyId)) //because iis cert install doesn't like to copy all properties from //request cert to install cert we just copy selected properties for now if (IsDesiredProperty(dwPropertyId)) { fSetting = TRUE; while (TRUE) { if (!CertGetCertificateContextProperty( pCertContextRequest, dwPropertyId, blobProp.pbData, &blobProp.cbData)) { //no get, no set, go on fSetting = FALSE; break; } if (NULL != blobProp.pbData) { //done break; } blobProp.pbData = (BYTE*)LocalAlloc(LMEM_FIXED, blobProp.cbData); if (NULL == blobProp.pbData) { goto OutOfMemoryError; } } if (fSetting) { //should get the property from the request cert if (!CertSetCertificateContextProperty( pCertContextMsg, dwPropertyId, 0, &blobProp)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorSetMyCertPropError; } } if (NULL != blobProp.pbData) { //set for the next enum LocalFree(blobProp.pbData); blobProp.pbData = NULL; } } dwPropertyId = CertEnumCertificateContextProperties( pCertContextRequest, dwPropertyId); } // save this away in the cache if(m_pCertContextStatic != NULL) CertFreeCertificateContext(m_pCertContextStatic); m_pCertContextStatic = CertDuplicateCertificateContext(pCertContextMsg); //Bug #202557 for IE3.02 upd clients (xiaohs) if(NULL==hProv) { if(!CryptAcquireContext( &hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorAcquireContext; } } if( !CryptHashCertificate( hProv, //NULL Bug #202557 for IE3.02 upd clients (xiaohs) 0, X509_ASN_ENCODING, pCertContextMsg->pbCertEncoded, pCertContextMsg->cbCertEncoded, blobHash.pbData, &blobHash.cbData) ) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCryptHashCertificate; } } // at this point we have 2 context m_pCertContextStatic which we want to return to the user // and pCertContextMsg which we want to delete from the Msg store assert(pCertContextMsg != NULL); CertDeleteCertificateFromStore(pCertContextMsg); pCertContextMsg = NULL; // freed by the delete // we want to return our static, so make a dup and this is what we will return assert(m_pCertContextStatic != NULL); pCertContextMsg = CertDuplicateCertificateContext(m_pCertContextStatic); // put these in the stores if asked if(fSaveToStores) { // open the stores if( (hStoreMy = GetStore(StoreMY)) == NULL) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertOpenMYStore; } // we know that the pCertContextMsg is a dup of the end-entity cert in m_pCertContextStatic // and we want to put this in the MY store assert(pCertContextMsg != NULL); if( !MySafeCertAddCertificateContextToStore( hStoreMy, pCertContextMsg, CERT_STORE_ADD_USE_EXISTING, NULL, m_dwEnabledSafteyOptions) ) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertAddToMyStore; } // If we have renewal, then mark the old cert as an archive if(m_fArchiveOldCert && ((pCertContextArchive = CertFindCertificateInStore( hStoreMy, X509_ASN_ENCODING, 0, CERT_FIND_HASH, &blobHashRenew, NULL)) != NULL) ) { // Set the Archive property on the cert. // crypt32 in IE3.02upd does not support this prop, so don't fail on error CertSetCertificateContextProperty( pCertContextArchive, CERT_ARCHIVED_PROP_ID, 0, &blobData); //set new cert hash on old archived cert //ignore error if it fails CertSetCertificateContextProperty( pCertContextArchive, CERT_RENEWAL_PROP_ID, 0, &blobHash); } // add the rest of the certs to the stores hr = AddCertsToStores(hStoreMsg, NULL); //ignore cancel error since it from root cert install //ignore XENROLL_E_CANNOT_ADD_ROOT_CERT also if (S_OK != hr && MY_HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr && XENROLL_E_CANNOT_ADD_ROOT_CERT != hr) { goto ErrorAddCertsToStores; } } *ppCert = pCertContextMsg; CommonReturn: //Bug #202557 for IE3.02 upd clients (xiaohs) if(hProv) CryptReleaseContext(hProv, 0); if(pCertContextRequest != NULL) CertFreeCertificateContext(pCertContextRequest); if(pCertContextArchive != NULL) CertFreeCertificateContext(pCertContextArchive); // it really should be NULL assert(pCertContextLast == NULL); if(hStoreMsg != NULL) CertCloseStore(hStoreMsg, 0); // we need to do this because the store that may be opened is the systemstore, but // the store we may need is the local machine store, but we don't know that until the // system store finds the request cert in the local machine physical store. // Later when we do the delete, we want the local machine store open. FlushStore(StoreREQUEST); if (NULL != requestFlagsBlob.pbData) { LocalFree(requestFlagsBlob.pbData); } if (NULL != renewalCertBlob.pbData) { LocalFree(renewalCertBlob.pbData); } if (NULL != blobProp.pbData) { LocalFree(blobProp.pbData); } if (NULL != pKeyProvInfo) { LocalFree(pKeyProvInfo); } if (NULL != pbArchivedKeyHash) { LocalFree(pbArchivedKeyHash); } LeaveCriticalSection(&m_csXEnroll); return (hr); ErrorReturn: if(NULL != pCertContextMsg) { CertFreeCertificateContext(pCertContextMsg); } goto CommonReturn; TRACE_ERROR(ErrorCryptHashCertificate); TRACE_ERROR(ErrorCertOpenMYStore); TRACE_ERROR(ErrorCertAddToMyStore); TRACE_ERROR(ErrorCryptQueryObject); TRACE_ERROR(ErrorCertOpenRequestStore); TRACE_ERROR(ErrorNoCertFound); TRACE_ERROR(ErrorCertGetCertificateContextProperty); TRACE_ERROR(ErrorSetMyCertPropError); TRACE_ERROR(ErrorDecodeRequestFlags); TRACE_ERROR(ErrorAcquireContext); //Bug #202557 for IE3.02 upd clients (xiaohs) TRACE_ERROR(ErrorAddCertsToStores); TRACE_ERROR(OutOfMemoryError); TRACE_ERROR(InvalidParameterError); TRACE_ERROR(ResponseKAMismatchError) TRACE_ERROR(ResponseUnexpectedKAHashError) TRACE_ERROR(ResponseKAHashNotFoundError) } HRESULT STDMETHODCALLTYPE CCEnroll::getCertFromPKCS7( /* [in] */ BSTR wszPKCS7, /* [retval][out] */ BSTR __RPC_FAR *pbstrCert ) { HRESULT hr; CRYPT_DATA_BLOB blobPKCS7; CRYPT_DATA_BLOB blobX509; PCCERT_CONTEXT pCertContextMy = NULL; assert(wszPKCS7 != NULL && pbstrCert != NULL); if (NULL == wszPKCS7 || NULL == pbstrCert) goto PointerError; // just put into a blob memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB)); blobPKCS7.cbData = SysStringByteLen(wszPKCS7); blobPKCS7.pbData = (PBYTE) wszPKCS7; // Get a Cert Context for the end-entity if( (pCertContextMy = getCertContextFromPKCS7(&blobPKCS7)) == NULL) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto getCertContextFromPKCS7Error; } blobX509.pbData = pCertContextMy->pbCertEncoded; blobX509.cbData = pCertContextMy->cbCertEncoded; //base64 with no header for backward compatible hr = BlobToBstring(&blobX509, CRYPT_STRING_BASE64, pbstrCert); if (S_OK != hr) { goto BlobToBstringError; } hr = S_OK; ErrorReturn: if(pCertContextMy != NULL) CertFreeCertificateContext(pCertContextMy); return(hr); SET_HRESULT(PointerError, E_POINTER); TRACE_ERROR(getCertContextFromPKCS7Error); TRACE_ERROR(BlobToBstringError); } HRESULT STDMETHODCALLTYPE CCEnroll::acceptPKCS7( /* [in] */ BSTR wszPKCS7) { CRYPT_DATA_BLOB blobPKCS7; HRESULT hr; assert(wszPKCS7 != NULL); if (NULL == wszPKCS7) goto PointerError; // just put into a blob memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB)); blobPKCS7.cbData = SysStringByteLen(wszPKCS7); blobPKCS7.pbData = (PBYTE) wszPKCS7; // accept the blob hr = acceptPKCS7Blob(&blobPKCS7); ErrorReturn: return hr; SET_HRESULT(PointerError, E_POINTER); } HRESULT STDMETHODCALLTYPE CCEnroll::createFilePKCS10( /* [in] */ BSTR DNName, /* [in] */ BSTR Usage, /* [in] */ BSTR wszPKCS10FileName) { return(createFilePKCS10WStr(DNName, Usage, wszPKCS10FileName)); } HRESULT STDMETHODCALLTYPE CCEnroll::addCertTypeToRequest( /* [in] */ BSTR CertType) { return(AddCertTypeToRequestWStr(CertType)); } HRESULT STDMETHODCALLTYPE CCEnroll::addCertTypeToRequestEx( IN LONG lType, IN BSTR bstrOIDOrName, IN LONG lMajorVersion, IN BOOL fMinorVersion, IN LONG lMinorVersion) { return AddCertTypeToRequestWStrEx( lType, bstrOIDOrName, lMajorVersion, fMinorVersion, lMinorVersion); } HRESULT STDMETHODCALLTYPE CCEnroll::getProviderType( IN BSTR strProvName, OUT LONG *plProvType) { return getProviderTypeWStr(strProvName, plProvType); } HRESULT STDMETHODCALLTYPE CCEnroll::addNameValuePairToSignature( /* [in] */ BSTR Name, /* [in] */ BSTR Value) { return(AddNameValuePairToSignatureWStr(Name, Value)); } HRESULT STDMETHODCALLTYPE CCEnroll::acceptFilePKCS7( /* [in] */ BSTR wszPKCS7FileName) { return(acceptFilePKCS7WStr(wszPKCS7FileName)); } HRESULT STDMETHODCALLTYPE CCEnroll::freeRequestInfo( /* [in] */ BSTR bstrPKCS7OrPKCS10) { HRESULT hr; CRYPT_DATA_BLOB blob; BYTE *pbData = NULL; DWORD cbData = 0; // could be base64 while (TRUE) { if (!MyCryptStringToBinaryW( (WCHAR*)bstrPKCS7OrPKCS10, SysStringLen(bstrPKCS7OrPKCS10), CRYPT_STRING_ANY, pbData, &cbData, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptStringToBinaryWError; } if (NULL != pbData) { break; //done } pbData = (BYTE*)LocalAlloc(LMEM_FIXED, cbData); if (NULL == pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } blob.cbData = cbData; blob.pbData = pbData; hr = freeRequestInfoBlob(blob); if (S_OK != hr) { goto freeRequestInfoBlobError; } hr = S_OK; ErrorReturn: if (NULL != pbData) { LocalFree(pbData); } return hr; TRACE_ERROR(MyCryptStringToBinaryWError) TRACE_ERROR(OutOfMemoryError) TRACE_ERROR(freeRequestInfoBlobError) } // // MY STORE // HCERTSTORE STDMETHODCALLTYPE CCEnroll::getMyStore( void) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return NULL; } HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreName( /* [retval][out] */ BSTR __RPC_FAR *pbstrName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_MyStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*pbstrName = SysAllocString(m_MyStore.wszName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreName( /* [in] */ BSTR bstrName) { return(put_MyStoreNameWStr(bstrName)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreType( /* [retval][out] */ BSTR __RPC_FAR *pbstrType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstrType = BSTRFromMB(m_MyStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreType( /* [in] */ BSTR bstrType) { return(put_MyStoreTypeWStr(bstrType)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreFlags( /* [retval][out] */ LONG __RPC_FAR *pdwFlags) { EnterCriticalSection(&m_csXEnroll); *pdwFlags = m_MyStore.dwFlags; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } //-------------------------------------------------------------------------------- // // This method is only safe for scripting if it's parameter is safe. // See VerifyStoreFlagsSafeForScripting(). // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreFlags( /* [in] */ LONG dwFlags) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); // If we're marked as safe for scripting, see if the flags passed in are safe: if (0 != m_dwEnabledSafteyOptions && !VerifyStoreFlagsSafeForScripting(dwFlags)) goto AccessDeniedError; if(m_MyStore.hStore != NULL) hr = E_ACCESSDENIED; else { // set the my store flags m_MyStore.dwFlags = dwFlags; m_fMyStoreOpenFlagsModified = TRUE; m_keyProvInfo.dwFlags |= KeyLocationFromStoreLocation(dwFlags); // track the request store location to the my store, only if the request store has not been modified // do NOT set the modify bit for the request store, this is a default if(!m_fRequestStoreOpenFlagsModified) { m_RequestStore.dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK; m_RequestStore.dwFlags |= (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK); } } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreNameWStr( /* [out] */ LPWSTR __RPC_FAR *szwName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_MyStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*szwName = CopyWideString(m_MyStore.wszName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreNameWStr( /* [in] */ LPWSTR szwName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_MyStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_MyStore.wszName != wszMY) MyCoTaskMemFree(m_MyStore.wszName); if( (m_MyStore.wszName = CopyWideString(szwName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_MyStoreTypeWStr( /* [out] */ LPWSTR __RPC_FAR *szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szwType = WideFromMB(m_MyStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_MyStoreTypeWStr( /* [in] */ LPWSTR szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_MyStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_MyStore.szType != szSystemStore) MyCoTaskMemFree(m_MyStore.szType); if( (m_MyStore.szType = MBFromWide(szwType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } // // CA STORE // HCERTSTORE STDMETHODCALLTYPE CCEnroll::getCAStore( void) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return NULL; } HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreName( /* [retval][out] */ BSTR __RPC_FAR *pbstrName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_CAStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*pbstrName = SysAllocString(m_CAStore.wszName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreName( /* [in] */ BSTR bstrName) { return(put_CAStoreNameWStr(bstrName)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreType( /* [retval][out] */ BSTR __RPC_FAR *pbstrType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstrType = BSTRFromMB(m_CAStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreType( /* [in] */ BSTR bstrType) { return(put_CAStoreTypeWStr(bstrType)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreFlags( /* [retval][out] */ LONG __RPC_FAR *pdwFlags) { EnterCriticalSection(&m_csXEnroll); *pdwFlags = m_CAStore.dwFlags; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } //-------------------------------------------------------------------------------- // // This method is only safe for scripting if it's parameter is safe. // See VerifyStoreFlagsSafeForScripting(). // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreFlags( /* [in] */ LONG dwFlags) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); // If we're marked as safe for scripting, see if the flags passed in are safe: if (0 != m_dwEnabledSafteyOptions && !VerifyStoreFlagsSafeForScripting(dwFlags)) goto AccessDeniedError; if(m_CAStore.hStore != NULL) hr = E_ACCESSDENIED; else { m_fCAStoreOpenFlagsModified = TRUE; m_CAStore.dwFlags = dwFlags; } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreNameWStr( /* [out] */ LPWSTR __RPC_FAR *szwName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_CAStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*szwName = CopyWideString(m_CAStore.wszName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreNameWStr( /* [in] */ LPWSTR szwName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_CAStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_CAStore.wszName != wszCA) MyCoTaskMemFree(m_CAStore.wszName); if( (m_CAStore.wszName = CopyWideString(szwName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_CAStoreTypeWStr( /* [out] */ LPWSTR __RPC_FAR *szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szwType = WideFromMB(m_CAStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_CAStoreTypeWStr( /* [in] */ LPWSTR szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_CAStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_CAStore.szType != szSystemStore) MyCoTaskMemFree(m_CAStore.szType); if( (m_CAStore.szType = MBFromWide(szwType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } // // ROOT STORE // HCERTSTORE STDMETHODCALLTYPE CCEnroll::getROOTHStore( void) { SetLastError(ERROR_CALL_NOT_IMPLEMENTED); return NULL; } HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreName( /* [retval][out] */ BSTR __RPC_FAR *pbstrName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_RootStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*pbstrName = SysAllocString(m_RootStore.wszName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreName( /* [in] */ BSTR bstrName) { return(put_RootStoreNameWStr(bstrName)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreType( /* [retval][out] */ BSTR __RPC_FAR *pbstrType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstrType = BSTRFromMB(m_RootStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreType( /* [in] */ BSTR bstrType) { return(put_RootStoreTypeWStr(bstrType)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreFlags( /* [retval][out] */ LONG __RPC_FAR *pdwFlags) { EnterCriticalSection(&m_csXEnroll); *pdwFlags = m_RootStore.dwFlags; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } //-------------------------------------------------------------------------------- // // This method is only safe for scripting if it's parameter is safe. // See VerifyStoreFlagsSafeForScripting(). // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreFlags( /* [in] */ LONG dwFlags) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); // If we're marked as safe for scripting, see if the flags passed in are safe: if (0 != m_dwEnabledSafteyOptions) { // see if the caller passed safe flags: if (!VerifyStoreFlagsSafeForScripting(dwFlags)) goto AccessDeniedError; // extra check for root store: don't allow CERT_SYSTEM_STORE_LOCAL_MACHINE for the root store. // if they want to install a machine cert through script, it'll go to the CA store: // NOTE: we don't modify the store name if m_RootStore.hStore is NULL, as we'll return E_ACCESSDENIED // anyway, and we shouldn't modify this on error. if (NULL == m_RootStore.hStore) { if (dwFlags & CERT_SYSTEM_STORE_LOCAL_MACHINE) { m_RootStore.wszName = wszCA; } else { m_RootStore.wszName = wszROOT; } } } if(m_RootStore.hStore != NULL) hr = E_ACCESSDENIED; else { m_fRootStoreOpenFlagsModified = TRUE; m_RootStore.dwFlags = dwFlags; } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreNameWStr( /* [out] */ LPWSTR __RPC_FAR *szwName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_RootStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*szwName = CopyWideString(m_RootStore.wszName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreNameWStr( /* [in] */ LPWSTR szwName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_RootStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_RootStore.wszName != wszROOT && m_RootStore.wszName != wszCA) MyCoTaskMemFree(m_RootStore.wszName); if( (m_RootStore.wszName = CopyWideString(szwName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RootStoreTypeWStr( /* [out] */ LPWSTR __RPC_FAR *szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szwType = WideFromMB(m_RootStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_RootStoreTypeWStr( /* [in] */ LPWSTR szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_RootStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_RootStore.szType != szSystemStore) MyCoTaskMemFree(m_RootStore.szType); if( (m_RootStore.szType = MBFromWide(szwType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } // // REQUEST STORE // HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreName( /* [retval][out] */ BSTR __RPC_FAR *pbstrName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_RequestStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*pbstrName = SysAllocString(m_RequestStore.wszName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreName( /* [in] */ BSTR bstrName) { return(put_RequestStoreNameWStr(bstrName)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreType( /* [retval][out] */ BSTR __RPC_FAR *pbstrType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstrType = BSTRFromMB(m_RequestStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreType( /* [in] */ BSTR bstrType) { return(put_RequestStoreTypeWStr(bstrType)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreFlags( /* [retval][out] */ LONG __RPC_FAR *pdwFlags) { EnterCriticalSection(&m_csXEnroll); *pdwFlags = m_RequestStore.dwFlags; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } //-------------------------------------------------------------------------------- // // This method is only safe for scripting if it's parameter is safe. // See VerifyStoreFlagsSafeForScripting(). // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreFlags( /* [in] */ LONG dwFlags) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); // If we're marked as safe for scripting, see if the flags passed in are safe: if (0 != m_dwEnabledSafteyOptions && !VerifyStoreFlagsSafeForScripting(dwFlags)) goto AccessDeniedError; if(m_RequestStore.hStore != NULL) hr = E_ACCESSDENIED; else { // set the request store flags m_RequestStore.dwFlags = dwFlags; m_fRequestStoreOpenFlagsModified = TRUE; // track the My store location to the request store, only if the my store has not been modified // do NOT set the modify bit for the my store, this is a default if(!m_fMyStoreOpenFlagsModified) { m_MyStore.dwFlags &= ~CERT_SYSTEM_STORE_LOCATION_MASK; m_MyStore.dwFlags |= (dwFlags & CERT_SYSTEM_STORE_LOCATION_MASK); m_keyProvInfo.dwFlags |= KeyLocationFromStoreLocation(m_MyStore.dwFlags); } } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreNameWStr( /* [out] */ LPWSTR __RPC_FAR *szwName) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_RequestStore.wszName == NULL) return(ERROR_UNKNOWN_PROPERTY); if( (*szwName = CopyWideString(m_RequestStore.wszName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreNameWStr( /* [in] */ LPWSTR szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_RequestStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_RequestStore.wszName != wszREQUEST) MyCoTaskMemFree(m_RequestStore.wszName); if( (m_RequestStore.wszName = CopyWideString(szwType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RequestStoreTypeWStr( /* [out] */ LPWSTR __RPC_FAR *szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szwType = WideFromMB(m_RequestStore.szType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_RequestStoreTypeWStr( /* [in] */ LPWSTR szwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; if(m_RequestStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_RequestStore.szType != szSystemStore) MyCoTaskMemFree(m_RequestStore.szType); if( (m_RequestStore.szType = MBFromWide(szwType)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } // // Provider Stuff // HRESULT STDMETHODCALLTYPE CCEnroll::get_ContainerName( /* [retval][out] */ BSTR __RPC_FAR *pbstrContainer) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstrContainer = SysAllocString(m_keyProvInfo.pwszContainerName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ContainerName( /* [in] */ BSTR bstrContainer) { return(put_ContainerNameWStr(bstrContainer)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderName( /* [retval][out] */ BSTR __RPC_FAR *pbstrProvider) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstrProvider = SysAllocString(m_keyProvInfo.pwszProvName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderName( /* [in] */ BSTR bstrProvider) { return(put_ProviderNameWStr(bstrProvider)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderType( /* [retval][out] */ LONG __RPC_FAR *pdwType) { EnterCriticalSection(&m_csXEnroll); *pdwType = m_keyProvInfo.dwProvType; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderType( /* [in] */ LONG dwType) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_hProv != NULL) hr = E_ACCESSDENIED; else m_keyProvInfo.dwProvType = dwType; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::get_KeySpec( /* [retval][out] */ LONG __RPC_FAR *pdw) { EnterCriticalSection(&m_csXEnroll); *pdw = m_keyProvInfo.dwKeySpec; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_KeySpec( /* [in] */ LONG dwKeySpec) { HRESULT hr; EnterCriticalSection(&m_csXEnroll); if(m_hProv != NULL) { hr = E_ACCESSDENIED; goto NullProvError; } if (m_fSMIMESetByClient) { //SMIME is set by the client if (m_fEnableSMIMECapabilities && AT_SIGNATURE == dwKeySpec) { //try to set signature key spec also SMIME hr = XENROLL_E_KEYSPEC_SMIME_MISMATCH; goto MismatchError; } } else { //currently smime is not set by user //turn on SMIME for according to key spec m_fEnableSMIMECapabilities = (dwKeySpec == AT_KEYEXCHANGE); } m_keyProvInfo.dwKeySpec = dwKeySpec; m_fKeySpecSetByClient = TRUE; hr = S_OK; ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); TRACE_ERROR(NullProvError) TRACE_ERROR(MismatchError) } HRESULT STDMETHODCALLTYPE CCEnroll::get_ClientId( /* [retval][out] */ LONG __RPC_FAR *pdw) { EnterCriticalSection(&m_csXEnroll); *pdw = m_lClientId; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ClientId( /* [in] */ LONG dw) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); m_lClientId = dw; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::get_IncludeSubjectKeyID( /* [retval][out] */ BOOL __RPC_FAR *pfInclude) { EnterCriticalSection(&m_csXEnroll); *pfInclude = m_fIncludeSubjectKeyID; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_IncludeSubjectKeyID( /* [in] */ BOOL fInclude) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); m_fIncludeSubjectKeyID = fInclude; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderFlags( /* [retval][out] */ LONG __RPC_FAR *pdwFlags) { EnterCriticalSection(&m_csXEnroll); *pdwFlags = m_keyProvInfo.dwFlags; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } //-------------------------------------------------------------------------------- // // This method is only safe for scripting if it's parameter is safe. // See VerifyProviderFlagsSafeForScripting(). // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderFlags( /* [in] */ LONG dwFlags) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); // If we're marked as safe for scripting, see if the flags passed in are safe: if (0 != m_dwEnabledSafteyOptions && !VerifyProviderFlagsSafeForScripting(dwFlags)) goto AccessDeniedError; if(m_hProv != NULL) hr = E_ACCESSDENIED; else m_keyProvInfo.dwFlags = dwFlags; ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); SET_HRESULT(AccessDeniedError, E_ACCESSDENIED); } HRESULT STDMETHODCALLTYPE CCEnroll::get_ContainerNameWStr( /* [out] */ LPWSTR __RPC_FAR *szwContainer) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szwContainer = CopyWideString(m_keyProvInfo.pwszContainerName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ContainerNameWStr( /* [in] */ LPWSTR szwContainer) { HRESULT hr = S_OK; if(szwContainer == NULL) return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); EnterCriticalSection(&m_csXEnroll); if(m_hProv != NULL) hr = E_ACCESSDENIED; else { if( m_keyProvInfo.pwszContainerName != wszEmpty) MyCoTaskMemFree(m_keyProvInfo.pwszContainerName); if( (m_keyProvInfo.pwszContainerName = CopyWideString(szwContainer)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); } LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::get_ProviderNameWStr( /* [out] */ LPWSTR __RPC_FAR *szwProvider) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szwProvider = CopyWideString(m_keyProvInfo.pwszProvName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ProviderNameWStr( /* [in] */ LPWSTR szwProvider) { HRESULT hr = S_OK; if(szwProvider == NULL) return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); EnterCriticalSection(&m_csXEnroll); if(m_hProv != NULL) hr = E_ACCESSDENIED; else { if (0 != wcscmp(m_keyProvInfo.pwszProvName, szwProvider)) { if( m_keyProvInfo.pwszProvName != wszEmpty ) MyCoTaskMemFree(m_keyProvInfo.pwszProvName); if( (m_keyProvInfo.pwszProvName = CopyWideString(szwProvider)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); //one last thing, free/null cached prov handle if (NULL != m_hVerifyProv) { CryptReleaseContext(m_hVerifyProv, 0); m_hVerifyProv = NULL; } // csp is changed, reset key size cache m_dwXhgKeyLenMax = 0; m_dwXhgKeyLenMin = 0; m_dwXhgKeyLenDef = 0; m_dwXhgKeyLenInc = 0; m_dwSigKeyLenMax = 0; m_dwSigKeyLenMin = 0; m_dwSigKeyLenDef = 0; m_dwSigKeyLenInc = 0; } } LeaveCriticalSection(&m_csXEnroll); return(hr); } // // Other Stuff // HRESULT STDMETHODCALLTYPE CCEnroll::get_UseExistingKeySet( /* [retval][out] */ BOOL __RPC_FAR *fUseExistingKeys) { EnterCriticalSection(&m_csXEnroll); *fUseExistingKeys = m_fUseExistingKey; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_UseExistingKeySet( /* [in] */ BOOL fUseExistingKeys) { EnterCriticalSection(&m_csXEnroll); m_fUseExistingKey = fUseExistingKeys; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_GenKeyFlags( /* [retval][out] */ LONG __RPC_FAR * pdwFlags) { EnterCriticalSection(&m_csXEnroll); *pdwFlags = m_dwGenKeyFlags; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_GenKeyFlags( /* [in] */ LONG dwFlags) { EnterCriticalSection(&m_csXEnroll); m_dwGenKeyFlags = dwFlags; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_DeleteRequestCert( /* [retval][out] */ BOOL __RPC_FAR *fBool) { EnterCriticalSection(&m_csXEnroll); *fBool = m_fDeleteRequestCert; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_DeleteRequestCert( /* [in] */ BOOL fBool) { EnterCriticalSection(&m_csXEnroll); m_fDeleteRequestCert = fBool; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_WriteCertToCSP( /* [retval][out] */ BOOL __RPC_FAR *fBool) { EnterCriticalSection(&m_csXEnroll); *fBool = m_fWriteCertToCSP; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_WriteCertToCSP( /* [in] */ BOOL fBool) { EnterCriticalSection(&m_csXEnroll); m_fWriteCertToCSP = fBool; m_fWriteCertToCSPModified = TRUE; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_WriteCertToUserDS( /* [retval][out] */ BOOL __RPC_FAR *fBool) { EnterCriticalSection(&m_csXEnroll); *fBool = m_fWriteCertToUserDS; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::put_WriteCertToUserDS( /* [in] */ BOOL fBool) { if (0 != m_dwEnabledSafteyOptions) // not safe for scripting return E_ACCESSDENIED; EnterCriticalSection(&m_csXEnroll); m_fWriteCertToUserDS = fBool; m_fWriteCertToUserDSModified = TRUE; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_EnableT61DNEncoding( /* [retval][out] */ BOOL __RPC_FAR *fBool) { EnterCriticalSection(&m_csXEnroll); *fBool = (m_dwT61DNEncoding == CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG); LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_EnableT61DNEncoding( /* [in] */ BOOL fBool) { EnterCriticalSection(&m_csXEnroll); if(fBool) m_dwT61DNEncoding = CERT_NAME_STR_ENABLE_T61_UNICODE_FLAG; else m_dwT61DNEncoding = 0; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_SPCFileName( /* [retval][out] */ BSTR __RPC_FAR *pbstr) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstr = SysAllocString(m_wszSPCFileName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_SPCFileName( /* [in] */ BSTR bstr) { return(put_SPCFileNameWStr(bstr)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_PVKFileName( /* [retval][out] */ BSTR __RPC_FAR *pbstr) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*pbstr = SysAllocString(m_wszPVKFileName)) == NULL ) hr = E_OUTOFMEMORY; LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_PVKFileName( /* [in] */ BSTR bstr) { return(put_PVKFileNameWStr(bstr)); } HRESULT STDMETHODCALLTYPE CCEnroll::get_HashAlgorithm( /* [retval][out] */ BSTR __RPC_FAR *pbstr) { LPWSTR wszAlg = NULL; HRESULT hr = S_OK; assert(pbstr != NULL); *pbstr = NULL; if( (hr = get_HashAlgorithmWStr(&wszAlg)) == S_OK ) { if( (*pbstr = SysAllocString(wszAlg)) == NULL ) hr = E_OUTOFMEMORY; } if(wszAlg != NULL) MyCoTaskMemFree(wszAlg); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_HashAlgorithm( /* [in] */ BSTR bstr) { return(put_HashAlgorithmWStr(bstr)); } HRESULT STDMETHODCALLTYPE CCEnroll::enumContainers( /* [in] */ LONG dwIndex, /* [out][retval] */ BSTR __RPC_FAR *pbstr) { LPWSTR pwsz = NULL; HRESULT hr; assert(pbstr != NULL); if((hr = enumContainersWStr(dwIndex, &pwsz)) != S_OK) goto EnumContainerError; if( (*pbstr = SysAllocString(pwsz)) == NULL ) { hr = E_OUTOFMEMORY; goto ErrorSysAllocString; } hr = S_OK; ErrorReturn: if(pwsz != NULL) MyCoTaskMemFree(pwsz); return(hr); TRACE_ERROR(EnumContainerError); TRACE_ERROR(ErrorSysAllocString); } HRESULT STDMETHODCALLTYPE CCEnroll::enumProviders( /* [in] */ LONG dwIndex, /* [in] */ LONG dwFlags, /* [out][retval] */ BSTR __RPC_FAR *pbstrProvName) { HRESULT hr; LPWSTR pwszProvName = NULL; assert(pbstrProvName != NULL); *pbstrProvName = NULL; if( (hr = enumProvidersWStr(dwIndex, dwFlags, &pwszProvName)) != S_OK) goto EnumProvidersError; if( (*pbstrProvName = SysAllocString(pwszProvName)) == NULL ) { hr = E_OUTOFMEMORY; goto ErrorSysAllocString; } hr = S_OK; ErrorReturn: if(pwszProvName != NULL) MyCoTaskMemFree(pwszProvName); return(hr); TRACE_ERROR(EnumProvidersError); TRACE_ERROR(ErrorSysAllocString); } HRESULT STDMETHODCALLTYPE CCEnroll::createFilePKCS10WStr( /* [in] */ LPCWSTR DNName, /* [in] */ LPCWSTR Usage, /* [in] */ LPCWSTR wszPKCS10FileName) { HRESULT hr; BSTR bstrPKCS10 = NULL; // get the pkcs 10 if( (hr = createPKCS10WStrBStr( DNName, Usage, &bstrPKCS10)) != S_OK) { goto ErrorCreatePKCS10; } // save it to file hr = BStringToFile(bstrPKCS10, wszPKCS10FileName); if (S_OK != hr) { goto ErrorBStringToFile; } hr = S_OK; ErrorReturn: if(bstrPKCS10 != NULL) SysFreeString(bstrPKCS10); return(hr); TRACE_ERROR(ErrorBStringToFile); TRACE_ERROR(ErrorCreatePKCS10); } HRESULT STDMETHODCALLTYPE CCEnroll::acceptFilePKCS7WStr( /* [in] */ LPCWSTR wszPKCS7FileName) { HRESULT hr; CRYPT_DATA_BLOB blob; ZeroMemory(&blob, sizeof(blob)); hr = xeStringToBinaryFromFile( wszPKCS7FileName, &blob.pbData, &blob.cbData, CRYPT_STRING_ANY); if (S_OK != hr) { goto xeStringToBinaryFromFileError; } // accept the blob hr = acceptPKCS7Blob(&blob); ErrorReturn: if (NULL != blob.pbData) { MyCoTaskMemFree(blob.pbData); } return(hr); TRACE_ERROR(xeStringToBinaryFromFileError) } BOOL GetAlgAndBitLen( HCRYPTPROV hProv, ALG_ID * pAlg, DWORD * pdwBitLen, DWORD dwFlags) { static BOOL fNew = TRUE; PROV_ENUMALGS_EX enumAlgsEx; PROV_ENUMALGS enumAlgs; DWORD cb = 0; *pAlg = 0; *pdwBitLen = 0; if(fNew) { cb = sizeof(enumAlgsEx); if(CryptGetProvParam( hProv, PP_ENUMALGS_EX, (BYTE *) &enumAlgsEx, &cb, dwFlags)) { *pAlg = enumAlgsEx.aiAlgid; *pdwBitLen = enumAlgsEx.dwMaxLen; return(TRUE); } else if(dwFlags != 0) fNew = FALSE; else return(FALSE); } // otherwise do the old stuff cb = sizeof(PROV_ENUMALGS); if(CryptGetProvParam( hProv, PP_ENUMALGS, (BYTE *) &enumAlgs, &cb, dwFlags) ) { *pAlg = enumAlgs.aiAlgid; *pdwBitLen = enumAlgs.dwBitLen; return(TRUE); } return(FALSE); } HRESULT CreateSMimeExtension( IN HCRYPTPROV hProv, OUT BYTE **ppbSMime, OUT DWORD *pcbSMime) { #define CINCSMIMECAP 20 HRESULT hr; DWORD dwBitLen; DWORD i; DWORD cbE; BYTE *pbE = NULL; DWORD dwFlags; PCCRYPT_OID_INFO pOidInfo = NULL; CRYPT_SMIME_CAPABILITIES smimeCaps; DWORD crgsmimeCap = 0; ALG_ID AlgID; BYTE *pb = NULL; DWORD cb = 0; memset(&smimeCaps, 0, sizeof(CRYPT_SMIME_CAPABILITIES)); smimeCaps.rgCapability = (PCRYPT_SMIME_CAPABILITY) LocalAlloc(LPTR, CINCSMIMECAP * sizeof(CRYPT_SMIME_CAPABILITY)); if (NULL == smimeCaps.rgCapability) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } crgsmimeCap = CINCSMIMECAP; dwFlags = CRYPT_FIRST; //first item while (GetAlgAndBitLen(hProv, &AlgID, &dwBitLen, dwFlags)) { pbE = NULL; cbE = 0; dwFlags = 0; //next item if(ALG_CLASS_DATA_ENCRYPT == GET_ALG_CLASS(AlgID)) { if(AlgID == CALG_RC2 || AlgID == CALG_RC4) { // encode the usage while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, X509_INTEGER, &dwBitLen, pbE, // pbEncoded &cbE)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptEncodeObjectError; } if (NULL != pbE) { break; } pbE = (BYTE *)LocalAlloc(LPTR, cbE); if (NULL == pbE) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } } } else { continue; } // convert to an oid, pOidInfo = xeCryptFindOIDInfo( CRYPT_OID_INFO_ALGID_KEY, (void *) &AlgID, CRYPT_ENCRYPT_ALG_OID_GROUP_ID); if(NULL == pOidInfo) { // don't crash on an error, just say we don't known it. if (NULL != pbE) { LocalFree(pbE); } pbE = NULL; continue; } // make sure we have enough room if(smimeCaps.cCapability >= crgsmimeCap) { PCRYPT_SMIME_CAPABILITY pSmimeCapsTmp; //increment the size crgsmimeCap += CINCSMIMECAP; pSmimeCapsTmp = (PCRYPT_SMIME_CAPABILITY)LocalReAlloc( smimeCaps.rgCapability, crgsmimeCap * sizeof(CRYPT_SMIME_CAPABILITY), LMEM_MOVEABLE | LMEM_ZEROINIT); if(NULL == pSmimeCapsTmp) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } smimeCaps.rgCapability = pSmimeCapsTmp; } smimeCaps.rgCapability[smimeCaps.cCapability].pszObjId = (char *) pOidInfo->pszOID; smimeCaps.rgCapability[smimeCaps.cCapability].Parameters.pbData = pbE; smimeCaps.rgCapability[smimeCaps.cCapability].Parameters.cbData = cbE; smimeCaps.cCapability++; pbE = NULL; // We'll free pbE through the struct we just assigned. NULL out so we don't double-free. } // encode the capabilities while (TRUE) { if (!CryptEncodeObject( CRYPT_ASN_ENCODING, PKCS_SMIME_CAPABILITIES, &smimeCaps, pb, &cb)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptEncodeObjectError; } if (NULL != pb) { break; } pb = (BYTE *)LocalAlloc(LPTR, cb); } *ppbSMime = pb; *pcbSMime = cb; pb = NULL; hr = S_OK; ErrorReturn: if(NULL != smimeCaps.rgCapability) { for (i = 0; i < smimeCaps.cCapability; ++i) { if (NULL != smimeCaps.rgCapability[i].Parameters.pbData) { LocalFree(smimeCaps.rgCapability[i].Parameters.pbData); } } LocalFree(smimeCaps.rgCapability); } if(NULL != pb) { LocalFree(pb); } if (NULL != pbE) { LocalFree(pbE); } return hr; TRACE_ERROR(CryptEncodeObjectError) TRACE_ERROR(OutOfMemoryError) } #if DBG void DebugGetContainerSD(HCRYPTPROV hProv) { PSECURITY_DESCRIPTOR pSD = NULL; DWORD cbSD; while (TRUE) { if (!CryptGetProvParam( hProv, PP_KEYSET_SEC_DESCR, (BYTE*)pSD, &cbSD, DACL_SECURITY_INFORMATION)) { break; } if (NULL != pSD) { break; } pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, cbSD); if (NULL == pSD) { break; } } if (NULL != pSD) { LocalFree(pSD); } } #endif //DBG //get the current user sids HRESULT GetCurrentUserInfo( OUT PTOKEN_USER *ppUserInfo, OUT BOOL *pfAdmin) { HRESULT hr; PTOKEN_USER pUserInfo = NULL; DWORD dwSize = 0; HANDLE hToken = NULL; HANDLE hDupToken = NULL; PSID psidAdministrators = NULL; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; HANDLE hThread; HANDLE hProcess; //init *pfAdmin = FALSE; if (!AllocateAndInitializeSid( &siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psidAdministrators)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto AllocateAndInitializeSidError; } hThread = GetCurrentThread(); if (NULL == hThread) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetCurrentThreadError; } // Get the access token for current thread if (!OpenThreadToken( hThread, TOKEN_QUERY | TOKEN_DUPLICATE, FALSE, &hToken)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); if(HRESULT_FROM_WIN32(ERROR_NO_TOKEN) != hr) { goto OpenThreadTokenError; } //get process token instead hProcess = GetCurrentProcess(); if (NULL == hProcess) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetCurrentProcessError; } hToken = NULL; if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_DUPLICATE, &hToken)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto OpenProcessTokenError; } } // CheckTokenMembership must operate on impersonation token, so make one if (!DuplicateToken(hToken, SecurityIdentification, &hDupToken)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto DuplicateTokenError; } if (!MyCheckTokenMembership(hDupToken, psidAdministrators, pfAdmin)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CheckTokenMembershipError; } //get current user sid while (TRUE) { if (!GetTokenInformation( hToken, TokenUser, pUserInfo, dwSize, &dwSize)) { if (NULL != pUserInfo || ERROR_INSUFFICIENT_BUFFER != GetLastError()) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetTokenInformationError; } } if (NULL != pUserInfo) { //done break; } pUserInfo = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, dwSize); if (NULL == pUserInfo) { hr = E_OUTOFMEMORY; goto LocalAllocError; } } if (NULL != ppUserInfo) { *ppUserInfo = pUserInfo; pUserInfo = NULL; } hr = S_OK; ErrorReturn: if (NULL != pUserInfo) { LocalFree(pUserInfo); } if (NULL != hToken) { CloseHandle(hToken); } if (NULL != hDupToken) { CloseHandle(hDupToken); } if (NULL != psidAdministrators) { FreeSid(psidAdministrators); } return hr; TRACE_ERROR(LocalAllocError) TRACE_ERROR(GetTokenInformationError) TRACE_ERROR(OpenProcessTokenError) TRACE_ERROR(GetCurrentProcessError) TRACE_ERROR(CheckTokenMembershipError) TRACE_ERROR(DuplicateTokenError) TRACE_ERROR(OpenThreadTokenError) TRACE_ERROR(GetCurrentThreadError) TRACE_ERROR(AllocateAndInitializeSidError) } HRESULT SetKeyContainerSecurityForNULLDacl( HCRYPTPROV hProv, DWORD dwFlags, PTOKEN_USER pUserInfo) { DWORD ccNeeded; HRESULT hr; LPWSTR wszSD = NULL; LPWSTR wszUserSid = NULL; PSECURITY_DESCRIPTOR pSD = NULL; UNREFERENCED_PARAMETER(dwFlags); // We want the security descriptor for the new keyset to look like so: // // ACES: // NT AUTHORITY\SYSTEM:F // BUILTIN\Administrators:F // // #define SDDL_NEW_KEYSET_START L"D:(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;" #define SDDL_NEW_KEYSET_END L")" if (!ConvertSidToStringSidW(pUserInfo->User.Sid, &wszUserSid)) { goto ConvertSidToStringSidError; } ccNeeded = (DWORD)(wcslen(SDDL_NEW_KEYSET_START) + wcslen(wszUserSid) + wcslen(SDDL_NEW_KEYSET_END) + 1); wszSD = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR)*ccNeeded); if (NULL == wszSD) { goto MemoryError; } wcscpy(wszSD, SDDL_NEW_KEYSET_START); wcscat(wszSD, wszUserSid); wcscat(wszSD, SDDL_NEW_KEYSET_END); if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(wszSD, SDDL_REVISION_1, &pSD, NULL)) { goto ConvertStringSecurityDescriptorToSecurityDescriptorWError; } if (!IsValidSecurityDescriptor(pSD)) { goto IsValidSecurityDescriptorError; } #if DBG DebugGetContainerSD(hProv); //just for ntsd debug #endif if (!CryptSetProvParam(hProv, PP_KEYSET_SEC_DESCR, (BYTE*)pSD, DACL_SECURITY_INFORMATION)) { goto CryptSetProvParamError; } #if DBG DebugGetContainerSD(hProv); //just for ntsd debug #endif hr = S_OK; ErrorReturn: if (NULL != wszSD) { LocalFree(wszSD); } if (NULL != wszUserSid) { LocalFree(wszUserSid); } if (NULL != pSD) { LocalFree(pSD); } return hr; SET_HRESULT(ConvertSidToStringSidError, HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(ConvertStringSecurityDescriptorToSecurityDescriptorWError, HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(CryptSetProvParamError, HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(IsValidSecurityDescriptorError, HRESULT_FROM_WIN32(ERROR_INVALID_SECURITY_DESCR)); SET_HRESULT(MemoryError, E_OUTOFMEMORY); } // This function ACLs new keysets (as 3rd party CSPs and downlevel CSPs may not do this correctly. // Should *not* call this function on existing keysets (as ACLs may have been set differently by admins) // HRESULT SetKeyContainerSecurity( HCRYPTPROV hProv, DWORD dwFlags) { HRESULT hr; PSECURITY_DESCRIPTOR pNewSD = NULL; PSECURITY_DESCRIPTOR pSD = NULL; DWORD cbSD; ACL_SIZE_INFORMATION AclInfo; PTOKEN_USER pUserInfo = NULL; PACL pNewAcl = NULL; LPVOID pAce; DWORD dwIndex; BYTE AceType; PACL pAcl; BOOL fDacl = TRUE; BOOL fDef = FALSE; BOOL fAdmin; BOOL fKeepSystemSid; BOOL fMachineKeySet = (0x0 != (dwFlags & CRYPT_MACHINE_KEYSET)) ? TRUE : FALSE; PSID pSidSystem = NULL; PSID pSidAdministrators = NULL; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; //get the current user info hr = GetCurrentUserInfo(&pUserInfo, &fAdmin); if (S_OK != hr) { goto GetCurrentUserInfoError; } //get the current sd from key container while (TRUE) { if (!CryptGetProvParam( hProv, PP_KEYSET_SEC_DESCR, (BYTE*)pSD, &cbSD, DACL_SECURITY_INFORMATION)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptGetProvParamError; } if (NULL != pSD) { break; } pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, cbSD); if (NULL == pSD) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } //get acl from sd if (!GetSecurityDescriptorDacl( pSD, &fDacl, &pAcl, &fDef)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetSecurityDescriptorDaclError; } if (!fDacl) { //if no dacl, quit hr = MY_HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); goto GetSecurityDescriptorDaclError; } if (NULL == pAcl) { #if 0 //this means allow everyone access the key which is unexpected, hr = SetKeyContainerSecurityForNULLDacl(hProv, dwFlags, pUserInfo); #endif // BUGBUG: The NULL DACL stuff doesn't work on downlevels because it requires SDDL. We don't // have time to fix for windows update, but we should revisit this later hr = S_OK; goto done; } //get acl info if (!GetAclInformation( pAcl, &AclInfo, sizeof(AclInfo), AclSizeInformation)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetAclInformationError; } //allocate enough for new dacl since we just remove aces pNewAcl = (PACL)LocalAlloc(LMEM_ZEROINIT, AclInfo.AclBytesInUse); if (NULL == pNewAcl) { hr = E_OUTOFMEMORY; goto LocalAllocError; } if (!InitializeAcl(pNewAcl, AclInfo.AclBytesInUse, ACL_REVISION)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto InitializeAclError; } fKeepSystemSid = fAdmin && fMachineKeySet; if (fKeepSystemSid) { //get system sid to later use if (!AllocateAndInitializeSid( &siaNtAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSidSystem)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto AllocateAndInitializeSidError; } } if (!AllocateAndInitializeSid(&siaNtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pSidAdministrators )) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto AllocateAndInitializeSidError; } //go through each ace, get only current user aces for (dwIndex = 0; dwIndex < AclInfo.AceCount; ++dwIndex) { if (!GetAce(pAcl, dwIndex, &pAce)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetAceError; } AceType = ((ACCESS_ALLOWED_ACE*)pAce)->Header.AceType; if (ACCESS_ALLOWED_ACE_TYPE == AceType) { if (EqualSid(pUserInfo->User.Sid, (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart)) || (fKeepSystemSid && EqualSid(pSidSystem, (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart))) || EqualSid(pSidAdministrators, (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart))) { //add current user ace or system ace into new acl if (!AddAccessAllowedAce( pNewAcl, ACL_REVISION, ((PACCESS_ALLOWED_ACE)pAce)->Mask, (PSID)&(((PACCESS_ALLOWED_ACE)pAce)->SidStart))) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto AddAccessAllowedAceError; } } } else if (ACCESS_DENIED_ACE_TYPE == AceType) { //add all deny ace into new acl if (!AddAccessDeniedAce( pNewAcl, ACL_REVISION, ((PACCESS_ALLOWED_ACE)pAce)->Mask, (PSID)&(((PACCESS_DENIED_ACE)pAce)->SidStart))) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto AddAccessDeniedAceError; } } } // initialize a security descriptor. pNewSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pNewSD == NULL) { hr = E_OUTOFMEMORY; goto LocalAllocError; } if (!InitializeSecurityDescriptor(pNewSD, SECURITY_DESCRIPTOR_REVISION)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto InitializeSecurityDescriptorError; } // add the ACL to the security descriptor. if (!SetSecurityDescriptorDacl( pNewSD, TRUE, // fDaclPresent flag pNewAcl, FALSE)) // not a default DACL { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto SetSecurityDescriptorDaclError; } //ok, set sd to be protected if (!MySetSecurityDescriptorControl( pNewSD, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto SetSecurityDescriptorControlError; } if (!IsValidSecurityDescriptor(pNewSD)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto IsValidSecurityDescriptorError; } #if DBG DebugGetContainerSD(hProv); //just for ntsd debug #endif //now we just set it if (!CryptSetProvParam( hProv, PP_KEYSET_SEC_DESCR, (BYTE*)pNewSD, DACL_SECURITY_INFORMATION)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptSetProvParamError; } #if DBG DebugGetContainerSD(hProv); //just for ntsd debug #endif done: hr = S_OK; ErrorReturn: if (NULL != pSD) { LocalFree(pSD); } if (NULL != pUserInfo) { LocalFree(pUserInfo); } if (NULL != pNewAcl) { LocalFree(pNewAcl); } if (NULL != pNewSD) { LocalFree(pNewSD); } if (NULL != pSidSystem) { FreeSid(pSidSystem); } if (NULL != pSidAdministrators) { FreeSid(pSidAdministrators); } return hr; TRACE_ERROR(CryptSetProvParamError) TRACE_ERROR(SetSecurityDescriptorDaclError) TRACE_ERROR(InitializeSecurityDescriptorError) TRACE_ERROR(LocalAllocError) TRACE_ERROR(AddAccessAllowedAceError) TRACE_ERROR(AddAccessDeniedAceError) TRACE_ERROR(GetAceError) TRACE_ERROR(GetCurrentUserInfoError) TRACE_ERROR(InitializeAclError) TRACE_ERROR(GetAclInformationError) TRACE_ERROR(GetSecurityDescriptorDaclError) TRACE_ERROR(OutOfMemoryError) TRACE_ERROR(CryptGetProvParamError) TRACE_ERROR(SetSecurityDescriptorControlError) TRACE_ERROR(IsValidSecurityDescriptorError) TRACE_ERROR(AllocateAndInitializeSidError) } HRESULT STDMETHODCALLTYPE CCEnroll::createPKCS10WStr( /* [in] */ LPCWSTR DNName, /* [in] */ LPCWSTR wszPurpose, /* [out] */ PCRYPT_DATA_BLOB pPkcs10Blob) { #define EndExt 5 #define EndAttr 6 HCRYPTPROV hProv = NULL; HCRYPTKEY hKey = NULL; CERT_REQUEST_INFO reqInfo; CERT_EXTENSIONS Extensions; PCERT_EXTENSION pExtCur = NULL; PCERT_EXTENSION rgExtension = NULL; CRYPT_ATTRIBUTE rgAttribute[EndAttr]; CRYPT_ATTR_BLOB blobExt; CRYPT_ATTR_BLOB blobCSPAttr; CRYPT_CSP_PROVIDER CSPProvider; CRYPT_ATTR_BLOB blobOSVAttr; CRYPT_ATTR_BLOB blobSMIMEPKCS7; CERT_NAME_VALUE cnvOSVer; OSVERSIONINFO osvInfo; DWORD iExt = 0; CRYPT_BIT_BLOB bbKeyUsage; BYTE bKeyUsage; CERT_SIGNED_CONTENT_INFO SignatureInfo; HRESULT hr = S_OK; DWORD errBefore = GetLastError(); PCCERT_CONTEXT pCertContext = NULL; HCERTSTORE hStore = NULL; DWORD ssFlags = 0; HANDLE hFile = NULL; CRYPT_DATA_BLOB blobData; DWORD cb = 0; char * pszPurpose = NULL; char * szStart = NULL; char * szEnd = NULL; char szVersion[45] = {0}; BOOL fAddCodeSign = FALSE; DWORD cPassedEKU = 0; DWORD i = 0; BOOL fRet; BYTE *pbSMime = NULL; BYTE *pbKU = NULL; BYTE *pbEKU = NULL; PPROP_STACK pProp; CRYPT_ATTR_BLOB blobClientId; DWORD cPublicKeyInfo = 0; BYTE *pbSubjectKeyHashExtension = NULL; DWORD cbSubjectKeyHashExtension = 0; DWORD dwErr; LPWSTR pwszNotSafeRequesting = NULL; LPWSTR pwszTitle = NULL; // // Declaration of extensions we need. The extensions with matching OIDs will be added // to the temporary cert context created by this method. // LPSTR rgszExtensionOIDs[] = { szOID_ENROLL_CERTTYPE_EXTENSION, szOID_CERTIFICATE_TEMPLATE }; // An array of the extensions we need to add to the certificate CERT_EXTENSION rgNeededExtensions[sizeof(rgszExtensionOIDs) / sizeof(LPSTR)]; // Need to put the array in a CERT_EXTENSIONS struct. CERT_EXTENSIONS ceExtensions; ceExtensions.rgExtension = &rgNeededExtensions[0]; ceExtensions.cExtension = 0; CRYPT_KEY_PROV_INFO keyProvInfoT; CERT_ENHKEY_USAGE enhKeyUsage; CRYPT_DATA_BLOB blobPKCS7; CRYPT_DATA_BLOB blobRenewAttr; RequestFlags requestFlags; CRYPT_DATA_BLOB requestInfoBlob; CRYPT_DATA_BLOB blobRenewalCert; ALG_ID rgAlg[2]; PCCRYPT_OID_INFO pOidInfo = NULL; EnterCriticalSection(&m_csXEnroll); // for the life of our procedure. SetLastError(ERROR_SUCCESS); assert(pPkcs10Blob != NULL); // clean out the PKCS 10 memset(&Extensions, 0, sizeof(CERT_EXTENSIONS)); memset(&rgAttribute, 0, sizeof(rgAttribute)); memset(&reqInfo, 0, sizeof(CERT_REQUEST_INFO)); memset(&SignatureInfo, 0, sizeof(SignatureInfo)); memset(&blobData, 0, sizeof(CRYPT_DATA_BLOB)); memset(&enhKeyUsage, 0, sizeof(CERT_ENHKEY_USAGE )); memset(pPkcs10Blob, 0, sizeof(CRYPT_DATA_BLOB)); memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB)); memset(&blobRenewAttr, 0, sizeof(CRYPT_DATA_BLOB)); memset(&requestFlags, 0, sizeof(RequestFlags)); memset(&requestInfoBlob, 0, sizeof(CRYPT_DATA_BLOB)); memset(&CSPProvider, 0, sizeof(CRYPT_CSP_PROVIDER)); memset(&cnvOSVer, 0, sizeof(CERT_NAME_VALUE)); memset(&osvInfo, 0, sizeof(OSVERSIONINFO)); memset(&blobSMIMEPKCS7, 0, sizeof(CRYPT_ATTR_BLOB)); memset(&rgNeededExtensions[0], 0, sizeof(rgNeededExtensions)); ZeroMemory(&blobExt, sizeof(blobExt)); memset(&blobCSPAttr, 0, sizeof(CRYPT_ATTR_BLOB)); memset(&blobOSVAttr, 0, sizeof(CRYPT_ATTR_BLOB)); memset(&blobClientId, 0, sizeof(CRYPT_ATTR_BLOB)); reqInfo.dwVersion = CERT_REQUEST_V1; // Creating a request is not safe for scripting: pop up a warning dialog if called from script if (0 != m_dwEnabledSafteyOptions) { hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle); if (S_OK != hr) { SetLastError(hr); goto xeLoadRCStringError; } hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_REQUESTING_CERT, &pwszNotSafeRequesting); if (S_OK != hr) { SetLastError(hr); goto xeLoadRCStringError; } if (IDYES != MessageBoxU(NULL, pwszNotSafeRequesting, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)) { hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); SetLastError(hr); goto CancelledError; } } if(!m_fUseExistingKey) { // attempt to get a new keyset if((hProv = GetProv(CRYPT_NEWKEYSET)) == NULL) { // in the hardware token case, there may only be a finite number of containers // if you run out, then use the default container. The Default container can // be specified by either a NULL or empty container name. // this is behavior requested by the smart cards, in particular smart card enrollment. if( m_fReuseHardwareKeyIfUnableToGenNew && GetLastError() == NTE_TOKEN_KEYSET_STORAGE_FULL) { // set it to the default container name if( m_keyProvInfo.pwszContainerName != wszEmpty ) MyCoTaskMemFree(m_keyProvInfo.pwszContainerName); m_keyProvInfo.pwszContainerName = wszEmpty; // say we want to use an exiting key. m_fUseExistingKey = TRUE; } else goto ErrorCryptAcquireContext; } } // if we are to use an existing key if(m_fUseExistingKey) { if((hProv = GetProv(0)) == NULL) goto ErrorCryptAcquireContext; } // we have the keyset, now make sure we have the key gen'ed if(!CryptGetUserKey( hProv, m_keyProvInfo.dwKeySpec, &hKey)) { //in case of smartcard csp, above call could be failed from //PIN Cancel button, don't go next to try genkey //also notice different csp could return different cancel errors dwErr = GetLastError(); if (SCARD_W_CANCELLED_BY_USER == dwErr || ERROR_CANCELLED == dwErr || ERROR_ACCESS_DENIED == dwErr) { goto CryptGetUserKeyCancelError; } // doesn't exist so gen it assert(hKey == NULL); // if the cached key is non-NULL, free it to prevent memory leaks if (NULL != m_hCachedKey) { CryptDestroyKey(m_hCachedKey); m_hCachedKey = NULL; } if(!CryptGenKey( hProv, m_keyProvInfo.dwKeySpec, m_dwGenKeyFlags | CRYPT_ARCHIVABLE, &m_hCachedKey) ) { //could be cancelled by user? don't make next try dwErr = GetLastError(); if (SCARD_W_CANCELLED_BY_USER == dwErr || ERROR_CANCELLED == dwErr || ERROR_ACCESS_DENIED == dwErr) { goto ErrorCryptGenKey; } //this error may be caused by not supporting CRYPT_ARCHIVABLE //we should check against error NTE_BAD_FLAGS but I doubt all //csps return consistent error code //let's try one more time without archivable flag assert(NULL == m_hCachedKey); DWORD dwGenKeyFlags = m_dwGenKeyFlags; if (NULL != m_PrivateKeyArchiveCertificate && m_fNewRequestMethod && (0 == (dwGenKeyFlags & CRYPT_EXPORTABLE))) { // We want ARCHIVABLE but not EXPORTABLE, so we needed the CRYPT_ARCHIVAL bit. Give up. goto ErrorCryptGenKey; } if (!CryptGenKey( hProv, m_keyProvInfo.dwKeySpec, dwGenKeyFlags, &hKey)) { goto ErrorCryptGenKey; } } //try to set key container ACL with owner ACE only (NOTE: only do this for creation!) hr = SetKeyContainerSecurity(hProv, m_keyProvInfo.dwFlags); #if DBG if (S_OK != hr) { goto SetKeyContainerSecurityError; } #endif //DBG hr = S_OK; //free build, no error checking here, if fails, live with it } if (NULL != hKey) { // don't need the hKey on existing key, so get rid of it CryptDestroyKey(hKey); } if ((NULL == m_PrivateKeyArchiveCertificate || !m_fNewRequestMethod) && NULL != m_hCachedKey) { //we don't need cache it, destroy it as soon as key is gen(ed) CryptDestroyKey(m_hCachedKey); m_hCachedKey = NULL; } // now get the public key out into m_pPublicKeyInfo // m_pPublicKeyInfo is internal use for cache if (NULL != m_pPublicKeyInfo) { LocalFree(m_pPublicKeyInfo); m_pPublicKeyInfo = NULL; } while (TRUE) { if(!CryptExportPublicKeyInfo(hProv, m_keyProvInfo.dwKeySpec, X509_ASN_ENCODING, m_pPublicKeyInfo, &cPublicKeyInfo)) { goto ErrorCryptExportPublicKeyInfo; } if (NULL != m_pPublicKeyInfo) { break; } m_pPublicKeyInfo = (PCERT_PUBLIC_KEY_INFO)LocalAlloc( LMEM_FIXED, cPublicKeyInfo); if (NULL == m_pPublicKeyInfo) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } reqInfo.SubjectPublicKeyInfo = *m_pPublicKeyInfo; // get the Subject DN only if one is specified reqInfo.Subject.pbData = NULL; while (TRUE) { if( !MyCertStrToNameW( CRYPT_ASN_ENCODING, DNName, 0 | m_dwT61DNEncoding, NULL, reqInfo.Subject.pbData, &reqInfo.Subject.cbData, NULL)) { if (CRYPT_E_INVALID_X500_STRING == GetLastError() && L'\0' == DNName[0]) { //this is likely on W95, W98, or NT4 with some IEs //crypt32 doesn't support empty DN conversion //hard code here reqInfo.Subject.cbData = 2; reqInfo.Subject.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, reqInfo.Subject.cbData); if (NULL == reqInfo.Subject.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } reqInfo.Subject.pbData[0] = 0x30; reqInfo.Subject.pbData[1] = 0x0; //done break; } else { goto ErrorCertStrToNameW; } } if (NULL != reqInfo.Subject.pbData) { break; } reqInfo.Subject.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, reqInfo.Subject.cbData); if (NULL == reqInfo.Subject.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } // allocate room for the extensions cb = (CountStackExtension(m_fNewRequestMethod) + EndExt) * sizeof(CERT_EXTENSION); rgExtension = (PCERT_EXTENSION)LocalAlloc(LMEM_FIXED, cb); if (NULL == rgExtension) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } memset(rgExtension, 0, cb); cb = 0; if (!m_fUseClientKeyUsage) { // Make Key Usage rgExtension[iExt].pszObjId = szOID_KEY_USAGE; rgExtension[iExt].fCritical = TRUE; // AT_SIGNATURE if( m_keyProvInfo.dwKeySpec == AT_SIGNATURE) bKeyUsage = CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERT_NON_REPUDIATION_KEY_USAGE; //AT_KEYEXCHANGE, limited for EMAIL single use // email may not work if signature is present else if(m_fLimitExchangeKeyToEncipherment) bKeyUsage = CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE; // AT_KEYEXCHANGE and AT_SIGNATURE dual key // This is the normal case for AT_KEYEXCHANGE since CAPI will sign with this. else bKeyUsage = CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE | CERT_DIGITAL_SIGNATURE_KEY_USAGE | CERT_NON_REPUDIATION_KEY_USAGE; bbKeyUsage.pbData = &bKeyUsage; bbKeyUsage.cbData = 1; bbKeyUsage.cUnusedBits = 1; // encode the usage rgExtension[iExt].Value.pbData = NULL; while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, X509_KEY_USAGE, &bbKeyUsage, pbKU, &rgExtension[iExt].Value.cbData)) { goto ErrorEncodeKeyUsage; } if (NULL != pbKU) { rgExtension[iExt].Value.pbData = pbKU; //done break; } pbKU = (BYTE *)LocalAlloc(LMEM_FIXED, rgExtension[iExt].Value.cbData); if (NULL == pbKU) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } iExt++; } if(m_fEnableSMIMECapabilities) { // add SMIME extension for symmetric algorithms rgExtension[iExt].pszObjId = szOID_RSA_SMIMECapabilities; rgExtension[iExt].fCritical = FALSE; hr = CreateSMimeExtension( hProv, &pbSMime, &rgExtension[iExt].Value.cbData); if (S_OK != hr) { goto CreateSMimeExtensionError; } rgExtension[iExt].Value.pbData = pbSMime; iExt++; } if (m_fHonorIncludeSubjectKeyID && m_fIncludeSubjectKeyID) { hr = myCreateSubjectKeyIdentifierExtension( m_pPublicKeyInfo, &pbSubjectKeyHashExtension, &cbSubjectKeyHashExtension); if (S_OK != hr) { goto myCreateSubjectKeyIdentifierExtensionError; } //add subject key ID hash extension into PKCS10 rgExtension[iExt].pszObjId = szOID_SUBJECT_KEY_IDENTIFIER; rgExtension[iExt].fCritical = FALSE; rgExtension[iExt].Value.pbData = pbSubjectKeyHashExtension; rgExtension[iExt].Value.cbData = cbSubjectKeyHashExtension; iExt++; } if(wszPurpose != NULL) { cb = 0; while (TRUE) { if(0 == (cb = WideCharToMultiByte( 0, 0, wszPurpose, -1, pszPurpose, cb, NULL, NULL))) { SetLastError(ERROR_OUTOFMEMORY); goto ErrorCantConvertPurpose; } if (NULL != pszPurpose) { break; } pszPurpose = (CHAR*)LocalAlloc(LMEM_FIXED, cb); if (NULL == pszPurpose) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } szStart = pszPurpose; // remove leading blanks while(*szStart == ',' || *szStart == ' ') *szStart++ = '\0'; while( szStart[0] != '\0' ) { // find the next string szEnd = szStart; while(*szEnd != ',' && *szEnd != ' ' && *szEnd != '\0') szEnd++; // remove trailing blanks while(*szEnd == ',' || *szEnd == ' ') *szEnd++ = '\0'; enhKeyUsage.cUsageIdentifier++; // see if this implies codesigning fAddCodeSign |= !strcmp(szStart, SPC_COMMERCIAL_SP_KEY_PURPOSE_OBJID) || !strcmp(szStart, SPC_INDIVIDUAL_SP_KEY_PURPOSE_OBJID); // go to next string szStart = szEnd; } // count the codesign EKU once cPassedEKU = enhKeyUsage.cUsageIdentifier; if(fAddCodeSign) enhKeyUsage.cUsageIdentifier++; // encode the extension if(enhKeyUsage.cUsageIdentifier != 0) { // allocate the EKU array enhKeyUsage.rgpszUsageIdentifier = (LPSTR *)LocalAlloc(LMEM_FIXED, enhKeyUsage.cUsageIdentifier * sizeof(LPSTR)); if (NULL == enhKeyUsage.rgpszUsageIdentifier) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } // add the EKU's szStart = pszPurpose; for(i=0; i= iExt); // now add all of the user defined extensions pExtCur = NULL; while(NULL != (pExtCur = EnumStackExtension(pExtCur, m_fNewRequestMethod)) ) { rgExtension[iExt] = *pExtCur; iExt++; } // fill in the extensions structure Extensions.cExtension = iExt; Extensions.rgExtension = rgExtension; // encode the extensions reqInfo.cAttribute = 0; reqInfo.rgAttribute = rgAttribute; while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, X509_EXTENSIONS, &Extensions, blobExt.pbData, // pbEncoded &blobExt.cbData)) { goto ErrorEncodeExtensions; } if (NULL != blobExt.pbData) { //got it, done break; } blobExt.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, blobExt.cbData); if (NULL == blobExt.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (m_fOID_V2) { //use new rsa oid rgAttribute[reqInfo.cAttribute].pszObjId = szOID_RSA_certExtensions; } else { //use microsoft oid for w2k clients rgAttribute[reqInfo.cAttribute].pszObjId = szOID_CERT_EXTENSIONS; } rgAttribute[reqInfo.cAttribute].cValue = 1; rgAttribute[reqInfo.cAttribute].rgValue = &blobExt; // put in the CSP attribute if( !GetSignatureFromHPROV( hProv, &CSPProvider.Signature.pbData, &CSPProvider.Signature.cbData ) ) goto ErrorGetSignatureFromHPROV; CSPProvider.pwszProviderName = m_keyProvInfo.pwszProvName; CSPProvider.dwKeySpec = m_keyProvInfo.dwKeySpec; while (TRUE) { if( !CryptEncodeObject( CRYPT_ASN_ENCODING, szOID_ENROLLMENT_CSP_PROVIDER, &CSPProvider, blobCSPAttr.pbData, // pbEncoded &blobCSPAttr.cbData)) { goto ErrorEncodeCSPAttr; } if (NULL != blobCSPAttr.pbData) { //got it, done break; } blobCSPAttr.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, blobCSPAttr.cbData); if (NULL == blobCSPAttr.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } reqInfo.cAttribute++; rgAttribute[reqInfo.cAttribute].pszObjId = szOID_ENROLLMENT_CSP_PROVIDER; rgAttribute[reqInfo.cAttribute].cValue = 1; rgAttribute[reqInfo.cAttribute].rgValue = &blobCSPAttr; // get the OSVersion osvInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if(!GetVersionExA(&osvInfo)) goto ErrorGetVersionEx; wsprintfA(szVersion, "%d.%d.%d.%d", osvInfo.dwMajorVersion, osvInfo.dwMinorVersion, osvInfo.dwBuildNumber, osvInfo.dwPlatformId); cnvOSVer.dwValueType = CERT_RDN_IA5_STRING; cnvOSVer.Value.cbData = (DWORD)strlen(szVersion); cnvOSVer.Value.pbData = (BYTE *) szVersion; while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, X509_ANY_STRING, &cnvOSVer, blobOSVAttr.pbData, // pbEncoded &blobOSVAttr.cbData)) { goto ErrorEncodeOSVAttr; } if (NULL != blobOSVAttr.pbData) { //got it, done break; } blobOSVAttr.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, blobOSVAttr.cbData); if (NULL == blobOSVAttr.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } reqInfo.cAttribute++; rgAttribute[reqInfo.cAttribute].pszObjId = szOID_OS_VERSION; rgAttribute[reqInfo.cAttribute].cValue = 1; rgAttribute[reqInfo.cAttribute].rgValue = &blobOSVAttr; // put in the renewal cert if present if(m_pCertContextRenewal != NULL && m_fHonorRenew) { reqInfo.cAttribute++; blobRenewAttr.pbData = m_pCertContextRenewal->pbCertEncoded; blobRenewAttr.cbData = m_pCertContextRenewal->cbCertEncoded; rgAttribute[reqInfo.cAttribute].pszObjId = szOID_RENEWAL_CERTIFICATE; rgAttribute[reqInfo.cAttribute].cValue = 1; rgAttribute[reqInfo.cAttribute].rgValue = &blobRenewAttr; } if (m_fNewRequestMethod && XECI_DISABLE != m_lClientId) { //put client id as attribute hr = myEncodeRequestClientAttributeFromClientId( m_lClientId, &blobClientId.pbData, &blobClientId.cbData); if (S_OK != hr) { //for any reasons, don't include client ID hr = put_ClientId(XECI_DISABLE); if (S_OK != hr) { goto putClientIdError; } } else { reqInfo.cAttribute++; rgAttribute[reqInfo.cAttribute].pszObjId = szOID_REQUEST_CLIENT_INFO; rgAttribute[reqInfo.cAttribute].cValue = 1; rgAttribute[reqInfo.cAttribute].rgValue = &blobClientId; } } // NOTE: On error we always return BAD ALGID // this is because sometimes we get an no more data enum error // that doesn't help. // get the signature oid if( !GetCapiHashAndSigAlgId(rgAlg) ) { SetLastError((DWORD)NTE_BAD_ALGID); goto ErrorGetCapiHashAndSigAlgId; } // Convert to an oid if( (NULL == (pOidInfo = xeCryptFindOIDInfo( CRYPT_OID_INFO_SIGN_KEY, (void *) rgAlg, CRYPT_SIGN_ALG_OID_GROUP_ID)) ) ) { SetLastError((DWORD)NTE_BAD_ALGID); goto ErrorCryptFindOIDInfo; } // we always know we have at least 1 attribute, and we have been zero based, now go to 1 based. reqInfo.cAttribute++; SignatureInfo.SignatureAlgorithm.pszObjId = (char *) pOidInfo->pszOID; #if DBG //SignatureInfo.ToBeSigned.pbData should be null at the first assert(NULL == SignatureInfo.ToBeSigned.pbData); #endif // encode PKCS10 while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, X509_CERT_REQUEST_TO_BE_SIGNED, &reqInfo, SignatureInfo.ToBeSigned.pbData, // pbEncoded &SignatureInfo.ToBeSigned.cbData)) { goto ErrorEncodePKCS10ToBeSigned; } if (NULL != SignatureInfo.ToBeSigned.pbData) { //done break; } SignatureInfo.ToBeSigned.pbData = (BYTE *) LocalAlloc(LMEM_FIXED, SignatureInfo.ToBeSigned.cbData); if (NULL == SignatureInfo.ToBeSigned.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } // create the signature Info // Don't care if xchange or signature key in dwkeySpec because // we are signing with the key that is in the PKCS10 #if DBG assert(NULL == SignatureInfo.Signature.pbData); #endif while (TRUE) { if(!CryptSignCertificate( hProv, m_keyProvInfo.dwKeySpec, CRYPT_ASN_ENCODING, SignatureInfo.ToBeSigned.pbData, SignatureInfo.ToBeSigned.cbData, &SignatureInfo.SignatureAlgorithm, NULL, // reserved SignatureInfo.Signature.pbData, // pbSignature &SignatureInfo.Signature.cbData)) { goto ErrorCryptSignCertificatePKCS10; } if (NULL != SignatureInfo.Signature.pbData) { //done break; } SignatureInfo.Signature.pbData = (BYTE *) LocalAlloc(LMEM_FIXED, SignatureInfo.Signature.cbData); if (NULL == SignatureInfo.Signature.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } // encode the final signed request if( !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_CERT, &SignatureInfo, NULL, &pPkcs10Blob->cbData ) || (pPkcs10Blob->pbData = (BYTE *) MyCoTaskMemAlloc(pPkcs10Blob->cbData)) == NULL || !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_CERT, &SignatureInfo, pPkcs10Blob->pbData, &pPkcs10Blob->cbData ) ) { goto ErrorEncodePKCS10Request; } // go ahead and make the pkcs 7 if((m_pCertContextRenewal != NULL || m_pCertContextSigner != NULL) && m_fHonorRenew && !m_fCMCFormat) //if CMC, don't make pkcs7 { // create a pkcs7 signed by the old cert if(S_OK != CreatePKCS7RequestFromRequest( pPkcs10Blob, (NULL != m_pCertContextRenewal) ? m_pCertContextRenewal : m_pCertContextSigner, &blobPKCS7) ) goto ErrorCreatePKCS7RARequestFromPKCS10; assert(pPkcs10Blob->pbData != NULL); MyCoTaskMemFree(pPkcs10Blob->pbData); *pPkcs10Blob = blobPKCS7; memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB)); } ssFlags = CERT_CREATE_SELFSIGN_NO_SIGN; if(m_wszPVKFileName[0] != 0) ssFlags |= CERT_CREATE_SELFSIGN_NO_KEY_INFO; // Get the cert extensions we wish to add to the certificate. // Search for the extensions we need. { PCERT_EXTENSION pCertExtCertTypeName = NULL; while(NULL != (pCertExtCertTypeName = EnumStackExtension(pCertExtCertTypeName, m_fNewRequestMethod)) ) { for (DWORD dTmp = 0; dTmp < sizeof(rgszExtensionOIDs) / sizeof(LPSTR); dTmp++) { if (0 == strcmp(rgszExtensionOIDs[dTmp], pCertExtCertTypeName->pszObjId)) rgNeededExtensions[(ceExtensions.cExtension)++] = *pCertExtCertTypeName; } } // Even if we didn't find all of the extensions we wanted, continue ... } assert(pCertContext == NULL); pCertContext = MyCertCreateSelfSignCertificate( hProv, &reqInfo.Subject, ssFlags, &m_keyProvInfo, NULL, NULL, NULL, (ceExtensions.cExtension > 0) ? &ceExtensions : NULL ); if (NULL == pCertContext) goto ErrorCertCreateSelfSignCertificate; // now put the pass thru data on the cert requestFlags.fWriteToCSP = (m_fWriteCertToCSP != 0); requestFlags.fWriteToDS = (m_fWriteCertToUserDS != 0); requestFlags.openFlags = m_RequestStore.dwFlags; #if DBG assert(NULL == requestInfoBlob.pbData); #endif while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, XENROLL_REQUEST_INFO, &requestFlags, requestInfoBlob.pbData, &requestInfoBlob.cbData)) { goto ErrorEncodeRequestInfoBlob; } if (NULL != requestInfoBlob.pbData) { //done break; } requestInfoBlob.pbData = (BYTE *)LocalAlloc(LMEM_FIXED, requestInfoBlob.cbData); if (NULL == requestInfoBlob.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } // set the property on the dummy request cert. if( !CertSetCertificateContextProperty( pCertContext, XENROLL_PASS_THRU_PROP_ID, 0, &requestInfoBlob) ) goto ErrorCertSetCertificateContextProperty; if(m_pCertContextRenewal != NULL && m_fHonorRenew) { blobRenewalCert.pbData = m_pCertContextRenewal->pbCertEncoded; blobRenewalCert.cbData = m_pCertContextRenewal->cbCertEncoded; // set the renewal property if any if( !CertSetCertificateContextProperty( pCertContext, XENROLL_RENEWAL_CERTIFICATE_PROP_ID, 0, &blobRenewalCert) ) goto ErrorCertSetCertificateContextProperty; } // save the private key away if needed if(m_wszPVKFileName[0] != 0) { // open the PVK File if( (hFile = CreateOpenFileSafely2(m_wszPVKFileName, IDS_PVK_C, IDS_PVK_O)) == NULL ) goto ErrorCreatePVKFile; assert(m_keyProvInfo.dwKeySpec == AT_SIGNATURE || m_keyProvInfo.dwKeySpec == AT_KEYEXCHANGE); // write out the private key if( !PrivateKeySave( hProv, hFile, m_keyProvInfo.dwKeySpec, NULL, m_wszPVKFileName, 0 ) ) { goto ErrorPrivateKeySave; } // put a different kind of propery in the store that just points to the pvk file keyProvInfoT = m_keyProvInfo; keyProvInfoT.pwszContainerName = m_wszPVKFileName; if( !CreatePvkProperty(&keyProvInfoT, &blobData) ) goto ErrorCreatePvkProperty; // This is really not needed, it is only nice for other tools // like makecert or signcode to be able to look at a cert without // specifying a .PVK file if the cert points to the .pvk file. // So we don't care if this actually fail, which it will on Auth2 and // SP3 Crypt32.dll since Phil was so kind as to not allow any unknown property // to be set on the cert --- BAD PHIL! CertSetCertificateContextProperty( pCertContext, CERT_PVK_FILE_PROP_ID, 0, &blobData); // only delete the keyset if the key was not pre-existing // this is if we write it out to a PVK file only // This is safe for scripting since we just generated this and we are putting it to // a pvk file. We really aren't deleting the key. if (!m_fNewRequestMethod) { //keep old behavior for createPKCS10 call if(!m_fUseExistingKey) GetProv(CRYPT_DELETEKEYSET); } } //set all properties from the caller pProp = EnumStackProperty(NULL); while (NULL != pProp) { //goto request cert if (!CertSetCertificateContextProperty( pCertContext, pProp->lPropId, 0, &pProp->prop)) { goto ErrorCertSetCertificateContextProperty; } pProp = EnumStackProperty(pProp); } // open the request cert store if( (hStore = GetStore(StoreREQUEST)) == NULL) goto ErrorCertOpenRequestStore; //if old pending request exists, free it first fRet = CertFreeCertificateContext(m_pCertContextPendingRequest); #if DBG assert(fRet); #endif //DBG m_pCertContextPendingRequest = NULL; // save the temp cert if( !MySafeCertAddCertificateContextToStore( hStore, pCertContext, CERT_STORE_ADD_NEW, &m_pCertContextPendingRequest, m_dwEnabledSafteyOptions) ) { goto ErrorCertAddToRequestStore; } // Remove the cached HASH. if (m_hashBlobPendingRequest.pbData != NULL) { LocalFree(m_hashBlobPendingRequest.pbData); m_hashBlobPendingRequest.pbData = NULL; } CommonReturn: if(pCertContext != NULL) CertFreeCertificateContext(pCertContext); if(hFile != NULL) CloseHandle(hFile); if(blobData.pbData != NULL) MyCoTaskMemFree(blobData.pbData); if(blobPKCS7.pbData != NULL) MyCoTaskMemFree(blobPKCS7.pbData); if(CSPProvider.Signature.pbData) LocalFree(CSPProvider.Signature.pbData); if (NULL != pbSMime) { LocalFree(pbSMime); } if (NULL != reqInfo.Subject.pbData) { LocalFree(reqInfo.Subject.pbData); } if (NULL != rgExtension) { LocalFree(rgExtension); } if (NULL != pbKU) { LocalFree(pbKU); } if (NULL != pbEKU) { LocalFree(pbEKU); } if (NULL != pszPurpose) { LocalFree(pszPurpose); } if (NULL != enhKeyUsage.rgpszUsageIdentifier) { LocalFree(enhKeyUsage.rgpszUsageIdentifier); } if (NULL != blobExt.pbData) { LocalFree(blobExt.pbData); } if (NULL != blobCSPAttr.pbData) { LocalFree(blobCSPAttr.pbData); } if (NULL != blobOSVAttr.pbData) { LocalFree(blobOSVAttr.pbData); } if (NULL != SignatureInfo.ToBeSigned.pbData) { LocalFree(SignatureInfo.ToBeSigned.pbData); } if (NULL != SignatureInfo.Signature.pbData) { LocalFree(SignatureInfo.Signature.pbData); } if (NULL != requestInfoBlob.pbData) { LocalFree(requestInfoBlob.pbData); } if (NULL != blobClientId.pbData) { LocalFree(blobClientId.pbData); } if (NULL != pbSubjectKeyHashExtension) { LocalFree(pbSubjectKeyHashExtension); } if (NULL != pwszNotSafeRequesting) { LocalFree(pwszNotSafeRequesting); } if (NULL != pwszTitle) { LocalFree(pwszTitle); } // don't know if we have an error or not // but I do know the errBefore is set properly SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); // on error return a NULL if(pPkcs10Blob->pbData != NULL) MyCoTaskMemFree(pPkcs10Blob->pbData); memset(pPkcs10Blob, 0, sizeof(CRYPT_DATA_BLOB)); goto CommonReturn; TRACE_ERROR(ErrorGetSignatureFromHPROV); TRACE_ERROR(ErrorEncodeCSPAttr); TRACE_ERROR(ErrorCertSetCertificateContextProperty); TRACE_ERROR(ErrorCryptAcquireContext); TRACE_ERROR(ErrorCryptGenKey); TRACE_ERROR(ErrorCryptExportPublicKeyInfo); TRACE_ERROR(ErrorCertStrToNameW); TRACE_ERROR(ErrorEncodeKeyUsage); TRACE_ERROR(ErrorEncodeEnhKeyUsage); TRACE_ERROR(ErrorEncodeExtensions); TRACE_ERROR(ErrorEncodePKCS10ToBeSigned); TRACE_ERROR(ErrorCryptSignCertificatePKCS10); TRACE_ERROR(ErrorEncodePKCS10Request); TRACE_ERROR(ErrorCantConvertPurpose); TRACE_ERROR(ErrorCertOpenRequestStore); TRACE_ERROR(ErrorCertAddToRequestStore); TRACE_ERROR(ErrorCreatePVKFile); TRACE_ERROR(ErrorPrivateKeySave); TRACE_ERROR(ErrorCreatePvkProperty); TRACE_ERROR(ErrorCertCreateSelfSignCertificate); TRACE_ERROR(ErrorEncodeRequestInfoBlob); TRACE_ERROR(ErrorCreatePKCS7RARequestFromPKCS10); TRACE_ERROR(ErrorGetCapiHashAndSigAlgId); TRACE_ERROR(ErrorCryptFindOIDInfo); TRACE_ERROR(ErrorEncodeOSVAttr); TRACE_ERROR(ErrorGetVersionEx); TRACE_ERROR(CancelledError); TRACE_ERROR(CreateSMimeExtensionError); TRACE_ERROR(OutOfMemoryError); TRACE_ERROR(putClientIdError); TRACE_ERROR(myCreateSubjectKeyIdentifierExtensionError) TRACE_ERROR(xeLoadRCStringError); TRACE_ERROR(CryptGetUserKeyCancelError) #if DBG TRACE_ERROR(SetKeyContainerSecurityError) #endif //DBG } HRESULT STDMETHODCALLTYPE CCEnroll::acceptPKCS7Blob( /* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7) { HRESULT hr; HRESULT hr2 = S_OK; LONG dwKeySpec = 0; PCCERT_CONTEXT pCertContextMy = NULL; PCCERT_CONTEXT pCertContextRequest = NULL; PCCERT_CONTEXT pCertContextEnd = NULL; HANDLE hFile = NULL; DWORD cb = 0; HCRYPTPROV hProv = NULL; HCRYPTKEY hKey = NULL; HCERTSTORE hStoreDS = NULL; HCERTSTORE hStoreRequest = NULL; HCERTSTORE hStoreMy = NULL; LPWSTR pwszTitle = NULL; LPWSTR pwszNotSafeAccepting = NULL; EnterCriticalSection(&m_csXEnroll); // Accepting a request is not safe for scripting: pop up a warning dialog if called from script if (0 != m_dwEnabledSafteyOptions) { hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle); if (S_OK != hr) goto xeLoadRCStringError; hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_ACCEPTING_CERT, &pwszNotSafeAccepting); if (S_OK != hr) goto xeLoadRCStringError; if (IDYES != MessageBoxU(NULL, pwszNotSafeAccepting, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)) { hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); goto CancelledError; } } // get the end entity cert hr2 = GetEndEntityCert(pBlobPKCS7, TRUE, &pCertContextEnd); if (S_OK != hr2 && XENROLL_E_CANNOT_ADD_ROOT_CERT != hr2) { hr = hr2; goto ErrorGetEndEntityCert; } if(m_fDeleteRequestCert) { if ((hStoreRequest = GetStore(StoreREQUEST)) == NULL) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertOpenRequestStore; } // check to see if this is in the request store if ((pCertContextRequest = CertFindCertificateInStore( hStoreRequest, CRYPT_ASN_ENCODING, 0, CERT_FIND_PUBLIC_KEY, (void *) &pCertContextEnd->pCertInfo->SubjectPublicKeyInfo, NULL)) != NULL) { CertDeleteCertificateFromStore(pCertContextRequest); pCertContextRequest = NULL; } } cb = 0; // if the cert is to be written to the CSP, // put it there but only if we have keys if (m_fWriteCertToCSP && CertGetCertificateContextProperty( pCertContextEnd, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb)) { if ((hProv = GetProv(0)) == NULL) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCryptAcquireContext; } // This can't fail get_KeySpec(&dwKeySpec); if (!CryptGetUserKey( hProv, dwKeySpec, &hKey)) { hKey = NULL; hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCryptGetUserKey; } // always attempt to write the cert to the csp if (!CryptSetKeyParam( hKey, KP_CERTIFICATE, pCertContextEnd->pbCertEncoded, 0)) { // only return an error if it is a smart card error // otherwise ignore the error if (SCODE_FACILITY(GetLastError()) == FACILITY_SCARD) { //return error code from writing cert to csp //important to save the error code before following clean up hr = MY_HRESULT_FROM_WIN32(GetLastError()); //if can't write cert back to smartcard, remove the cert from my store if ((hStoreMy = GetStore(StoreMY)) == NULL) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertOpenMyStore; } // check to see if this is in the MY store if ((pCertContextMy = CertFindCertificateInStore( hStoreMy, CRYPT_ASN_ENCODING, 0, CERT_FIND_PUBLIC_KEY, (void *) &pCertContextEnd->pCertInfo->SubjectPublicKeyInfo, NULL)) != NULL) { //try to remove it CertDeleteCertificateFromStore(pCertContextMy); pCertContextMy = NULL; } if (!m_fUseExistingKey) { GetProv(CRYPT_DELETEKEYSET); } //error any way goto ErrorWriteToCSP; } } } if(m_fWriteCertToUserDS) { // otherwise attempt to open the store if ((hStoreDS = CertOpenStore( CERT_STORE_PROV_SYSTEM, X509_ASN_ENCODING, NULL, CERT_SYSTEM_STORE_CURRENT_USER, L"UserDS")) == NULL) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCertOpenDSStore; } if (!CertAddCertificateContextToStore( hStoreDS, pCertContextEnd, CERT_STORE_ADD_NEW, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorAddCertificateContextToDSStore; } CertCloseStore(hStoreDS, 0); hStoreDS = NULL; } // determine if he wants to save the spc file if (m_wszSPCFileName[0] != 0) { // open the spc file hFile = CreateOpenFileSafely2(m_wszSPCFileName, IDS_SPC_C, IDS_SPC_O); if (NULL == hFile) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorCreateSPCFile; } // write the spc assert(pBlobPKCS7->pbData != NULL); cb = 0; if (!WriteFile( hFile, pBlobPKCS7->pbData, pBlobPKCS7->cbData, &cb, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto ErrorWriteSPCFile; } } if (S_OK != hr2) { //return hr2 error hr = hr2; } else { hr = S_OK; } ErrorReturn: if(hKey != NULL) CryptDestroyKey(hKey); if(hFile != NULL) CloseHandle(hFile); if(pCertContextEnd != NULL) CertFreeCertificateContext(pCertContextEnd); if(hStoreDS != NULL) CertCloseStore(hStoreDS, 0); if (NULL != pwszNotSafeAccepting) LocalFree(pwszNotSafeAccepting); if (NULL != pwszTitle) LocalFree(pwszTitle); LeaveCriticalSection(&m_csXEnroll); return(hr); TRACE_ERROR(ErrorWriteToCSP); TRACE_ERROR(ErrorCreateSPCFile); TRACE_ERROR(ErrorWriteSPCFile); TRACE_ERROR(ErrorGetEndEntityCert); TRACE_ERROR(ErrorCryptAcquireContext); TRACE_ERROR(ErrorCryptGetUserKey); TRACE_ERROR(ErrorCertOpenDSStore); TRACE_ERROR(ErrorAddCertificateContextToDSStore); TRACE_ERROR(ErrorCertOpenRequestStore); TRACE_ERROR(ErrorCertOpenMyStore); TRACE_ERROR(CancelledError); TRACE_ERROR(xeLoadRCStringError); } PCCERT_CONTEXT STDMETHODCALLTYPE CCEnroll::getCertContextFromPKCS7( /* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7) { HRESULT hr; PCCERT_CONTEXT pCert; // get the end entity cert hr = GetEndEntityCert(pBlobPKCS7, FALSE, &pCert); #if DBG if (S_OK != hr) { assert(NULL == pCert); } #endif //DBG return pCert; } HRESULT STDMETHODCALLTYPE CCEnroll::enumProvidersWStr( /* [in] */ LONG dwIndex, /* [in] */ LONG dwFlags, /* [out] */ LPWSTR __RPC_FAR *ppwsz) { DWORD iLast = 0; LONG i; DWORD dwProvType = 0; DWORD cb = 0; HRESULT hr = S_OK; DWORD errBefore = GetLastError(); assert(ppwsz != NULL); *ppwsz = NULL; SetLastError(ERROR_SUCCESS); EnterCriticalSection(&m_csXEnroll); for(i=0; i<=dwIndex; i++) { do { cb = 0; if( !CryptEnumProvidersU( iLast, 0, 0, &dwProvType, NULL, &cb ) ) { // only skip if entry is bad if( GetLastError() != NTE_PROV_TYPE_ENTRY_BAD) goto ErrorCryptEnumProvidersU; } iLast++; } while((CRYPT_ENUM_ALL_PROVIDERS & dwFlags) != CRYPT_ENUM_ALL_PROVIDERS && dwProvType != m_keyProvInfo.dwProvType); } iLast--; if( (*ppwsz = (LPWSTR) MyCoTaskMemAlloc(cb)) == NULL || !CryptEnumProvidersU( iLast, 0, 0, &dwProvType, *ppwsz, &cb ) ) { goto ErrorCryptEnumProvidersU; } CommonReturn: SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); if(*ppwsz != NULL) { MyCoTaskMemFree(*ppwsz); *ppwsz = NULL; } goto CommonReturn; TRACE_ERROR(ErrorCryptEnumProvidersU); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::enumContainersWStr( /* [in] */ LONG dwIndex, /* [out] */ LPWSTR __RPC_FAR *ppwsz) { DWORD errBefore = GetLastError(); DWORD cb = 0; LONG i = 0; char * psz = NULL; HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); SetLastError(ERROR_SUCCESS); assert(ppwsz != NULL); *ppwsz = NULL; if (0 != m_dwEnabledSafteyOptions) // not safe for scripting goto AccessDeniedError; hr = GetVerifyProv(); if (S_OK != hr) { goto GetVerifyProvError; } while (TRUE) { if(!CryptGetProvParam( m_hVerifyProv, PP_ENUMCONTAINERS, (BYTE*)psz, &cb, CRYPT_FIRST)) { goto ErrorCryptGetProvParam; } if (NULL != psz) { //done break; } psz = (char*)LocalAlloc(LMEM_FIXED, cb); if (NULL == psz) { goto ErrorOutOfMem; } } for(i=1; i<=dwIndex; i++) { //assume 1st enum buffer size is big enough for all? if( !CryptGetProvParam( m_hVerifyProv, PP_ENUMCONTAINERS, (BYTE *) psz, &cb, 0) ) goto ErrorCryptGetProvParam; } if( (*ppwsz = WideFromMB(psz)) == NULL ) goto ErrorOutOfMem; CommonReturn: if (NULL != psz) { LocalFree(psz); } SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); if(*ppwsz != NULL) MyCoTaskMemFree(*ppwsz); *ppwsz = NULL; goto CommonReturn; SET_ERROR(AccessDeniedError, E_ACCESSDENIED); TRACE_ERROR(GetVerifyProvError); TRACE_ERROR(ErrorCryptGetProvParam); TRACE_ERROR(ErrorOutOfMem); } HRESULT CCEnroll::PKCS10ToCert(IN HCERTSTORE hCertStore, IN CRYPT_DATA_BLOB pkcs10Blob, OUT PCCERT_CONTEXT *ppCertContext) { HRESULT hr = E_FAIL; PCERT_REQUEST_INFO pReqInfo = NULL; // Input validation: if (NULL == hCertStore || NULL == pkcs10Blob.pbData || NULL == ppCertContext) return E_INVALIDARG; if( !MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pkcs10Blob, CERT_QUERY_CONTENT_FLAG_PKCS10, CERT_QUERY_FORMAT_FLAG_ALL, CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, NULL, NULL, NULL, (const void **) &pReqInfo) ) goto MyCryptQueryObjectError; if ( NULL == (*ppCertContext = CertFindCertificateInStore (hCertStore, CRYPT_ASN_ENCODING, 0, CERT_FIND_PUBLIC_KEY, (void *) &pReqInfo->SubjectPublicKeyInfo, NULL)) ) goto CertFindCertificateInStoreError; hr = S_OK; CommonReturn: if (NULL != pReqInfo) { LocalFree(pReqInfo); } // Allocated in CryptQueryObject(). return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(CertFindCertificateInStoreError, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(MyCryptQueryObjectError, MY_HRESULT_FROM_WIN32(GetLastError())); } HRESULT CCEnroll::PKCS7ToCert(IN HCERTSTORE hCertStore, IN CRYPT_DATA_BLOB pkcs7Blob, OUT PCCERT_CONTEXT *ppCertContext) { CRYPT_DATA_BLOB pkcs10Blob; CRYPT_VERIFY_MESSAGE_PARA VerifyPara; HRESULT hr = E_FAIL; // Init locals: ZeroMemory(&pkcs10Blob, sizeof(pkcs10Blob)); ZeroMemory(&VerifyPara, sizeof(VerifyPara)); VerifyPara.cbSize = sizeof(VerifyPara); VerifyPara.dwMsgAndCertEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; if (!MyCryptVerifyMessageSignature (&VerifyPara, 0, // dwSignerIndex pkcs7Blob.pbData, pkcs7Blob.cbData, pkcs10Blob.pbData, &(pkcs10Blob.cbData), NULL // ppSignerCert ) || 0 == pkcs10Blob.cbData) goto MyCryptVerifyMessageSignatureError; if (NULL == (pkcs10Blob.pbData = (PBYTE)LocalAlloc(LPTR, pkcs10Blob.cbData))) goto MemoryError; if (!MyCryptVerifyMessageSignature (&VerifyPara, 0, // dwSignerIndex pkcs7Blob.pbData, pkcs7Blob.cbData, pkcs10Blob.pbData, &pkcs10Blob.cbData, NULL // ppSignerCert )) goto MyCryptVerifyMessageSignatureError; hr = this->PKCS10ToCert(hCertStore, pkcs10Blob, ppCertContext); CommonReturn: if (NULL != pkcs10Blob.pbData) { LocalFree(pkcs10Blob.pbData); } return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(MemoryError, E_OUTOFMEMORY); SET_HRESULT(MyCryptVerifyMessageSignatureError, MY_HRESULT_FROM_WIN32(GetLastError())); } HRESULT STDMETHODCALLTYPE CCEnroll::freeRequestInfoBlob( /* [in] */ CRYPT_DATA_BLOB pkcs7OrPkcs10) { DWORD dwContentType = NULL; HCERTSTORE hStoreRequest = NULL; HRESULT hr = E_FAIL; PCCERT_CONTEXT pCertContext = NULL; // We're not supposed to delete the cert anyway, so we're done! if (!m_fDeleteRequestCert) return S_OK; if (NULL == pkcs7OrPkcs10.pbData) return E_INVALIDARG; EnterCriticalSection(&m_csXEnroll); // Step 1) Determine if we have a PKCS7 or a PKCS10: // if( !MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB, &pkcs7OrPkcs10, (CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_PKCS10), CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, &dwContentType, // OUT: PKCS10 or PKCS7 NULL, NULL, NULL, NULL) ) goto MyCryptQueryObjectError; // Step 2) Find a cert context with a matching public key in the request store: // if (NULL == (hStoreRequest = GetStore(StoreREQUEST))) goto UnexpectedError; switch (dwContentType) { case CERT_QUERY_CONTENT_PKCS7_SIGNED: hr = this->PKCS7ToCert(hStoreRequest, pkcs7OrPkcs10, &pCertContext); if (S_OK != hr) { if (CRYPT_E_NOT_FOUND == hr) { //freeRequestInfo could be called when cert is not issued //PKCS7 could be CMC which is signed by request key and //cert is not in local store yet. We try cached cert if (NULL != m_pCertContextPendingRequest) { //looks we still have cached request cert handle pCertContext = CertDuplicateCertificateContext( m_pCertContextPendingRequest); if (NULL == pCertContext) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertDuplicateCertificateContextError; } } else if (NULL != m_hashBlobPendingRequest.pbData && 0 < m_hashBlobPendingRequest.cbData) { //don't have cached request handle but thumbprint exists //retrieve the request cert handle from store pCertContext = CertFindCertificateInStore( hStoreRequest, //request store X509_ASN_ENCODING, 0, CERT_FIND_HASH, &m_hashBlobPendingRequest, NULL); if (NULL == pCertContext) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertFindCertificateInStoreError; } } else { //sorry, don't know which cert to be free //however, can try to find public key from PKCS7 goto PKCS7ToCertError; } } else { //other errors goto PKCS7ToCertError; } } break; case CERT_QUERY_CONTENT_PKCS10: if (S_OK != (hr = this->PKCS10ToCert(hStoreRequest, pkcs7OrPkcs10, &pCertContext))) goto PKCS10ToCertError; break; default: goto InvalidContentTypeError; } if (!CertDeleteCertificateFromStore(pCertContext)) { // pCertContext is freed even when CertDeleteCertificateFromStore() returns an error. pCertContext = NULL; goto CertDeleteCertificateFromStoreError; } hr = S_OK; CommonReturn: LeaveCriticalSection(&m_csXEnroll); return hr; ErrorReturn: if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); } goto CommonReturn; SET_HRESULT(CertDeleteCertificateFromStoreError, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(PKCS7ToCertError, hr); SET_HRESULT(PKCS10ToCertError, hr); SET_HRESULT(InvalidContentTypeError, E_INVALIDARG); SET_HRESULT(MyCryptQueryObjectError, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(UnexpectedError, E_UNEXPECTED); TRACE_ERROR(CertDuplicateCertificateContextError) TRACE_ERROR(CertFindCertificateInStoreError) } HRESULT STDMETHODCALLTYPE CCEnroll::get_SPCFileNameWStr( /* [out] */ LPWSTR __RPC_FAR *szw) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szw = CopyWideString(m_wszSPCFileName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_SPCFileNameWStr( /* [in] */ LPWSTR pwsz) { HRESULT hr = S_OK; if(pwsz == NULL) return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); EnterCriticalSection(&m_csXEnroll); if( m_wszSPCFileName != wszEmpty) MyCoTaskMemFree(m_wszSPCFileName); if( (m_wszSPCFileName = CopyWideString(pwsz)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::get_PVKFileNameWStr( /* [out] */ LPWSTR __RPC_FAR *szw) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if( (*szw = CopyWideString(m_wszPVKFileName)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_PVKFileNameWStr( /* [in] */ LPWSTR pwsz) { HRESULT hr = S_OK; if(pwsz == NULL) return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); EnterCriticalSection(&m_csXEnroll); if( m_wszPVKFileName != wszEmpty) MyCoTaskMemFree(m_wszPVKFileName); if( (m_wszPVKFileName = CopyWideString(pwsz)) == NULL ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); else m_dwGenKeyFlags |= CRYPT_EXPORTABLE; //why??? LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::get_HashAlgorithmWStr( /* [out] */ LPWSTR __RPC_FAR *ppwsz) { PCCRYPT_OID_INFO pOidInfo = NULL; ALG_ID rgAlg[2]; HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); assert(ppwsz != NULL); *ppwsz = NULL; if( !GetCapiHashAndSigAlgId(rgAlg) ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); // Convert to an oid else if( (NULL == (pOidInfo = xeCryptFindOIDInfo( CRYPT_OID_INFO_ALGID_KEY, (void *) &rgAlg[0], CRYPT_HASH_ALG_OID_GROUP_ID)) ) ) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); } else if( (*ppwsz = WideFromMB(pOidInfo->pszOID)) == NULL) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_HashAlgorithmWStr( /* [in] */ LPWSTR pwsz) { HRESULT hr = S_OK; char * szObjId = NULL; PCCRYPT_OID_INFO pOidInfo = NULL; if(pwsz == NULL) { return(MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER)); } if(!_wcsicmp(L"SHA1", pwsz)) szObjId = CopyAsciiString(szOID_OIWSEC_sha1); else if(!_wcsicmp(L"MD5", pwsz)) szObjId = CopyAsciiString(szOID_RSA_MD5RSA); else if(!_wcsicmp(L"MD2", pwsz)) szObjId = CopyAsciiString(szOID_RSA_MD2RSA); else szObjId = MBFromWide(pwsz); // something went wrong if(szObjId == NULL) return(MY_HRESULT_FROM_WIN32(GetLastError())); // find the hashing algid if( (NULL == (pOidInfo = xeCryptFindOIDInfo( CRYPT_OID_INFO_OID_KEY, szObjId, 0)) ) ) { //XIAOHS: CryptFindOIDInfo does not set the LastError in this case. //AV in xEnroll. See bug# 189320 //hr = MY_HRESULT_FROM_WIN32(GetLastError()); hr=NTE_BAD_ALGID; } assert(szObjId != NULL); MyCoTaskMemFree(szObjId); EnterCriticalSection(&m_csXEnroll); if(hr == S_OK) { if( pOidInfo->dwGroupId == CRYPT_HASH_ALG_OID_GROUP_ID || pOidInfo->dwGroupId == CRYPT_SIGN_ALG_OID_GROUP_ID ) m_HashAlgId = pOidInfo->Algid; else hr = CRYPT_E_NOT_FOUND; } LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_HashAlgID( LONG hashAlgID ) { EnterCriticalSection(&m_csXEnroll); m_HashAlgId = hashAlgID; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_HashAlgID( LONG * hashAlgID ) { EnterCriticalSection(&m_csXEnroll); *hashAlgID = m_HashAlgId; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_RenewalCertificate( /* [out] */ PCCERT_CONTEXT __RPC_FAR *ppCertContext) { HRESULT hr = S_OK; *ppCertContext = NULL; if( m_pCertContextRenewal == NULL) return(MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND)); EnterCriticalSection(&m_csXEnroll); if( NULL == (*ppCertContext = CertDuplicateCertificateContext(m_pCertContextRenewal)) ) hr = MY_HRESULT_FROM_WIN32(GetLastError()); LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_RenewalCertificate( /* [in] */ PCCERT_CONTEXT pCertContext) { HRESULT hr; PCCERT_CONTEXT pGoodCertContext= NULL; EnterCriticalSection(&m_csXEnroll); hr = GetGoodCertContext(pCertContext, &pGoodCertContext); if (S_OK != hr) { goto GetGoodCertContextError; } if(m_pCertContextRenewal != NULL) { CertFreeCertificateContext(m_pCertContextRenewal); } m_pCertContextRenewal = pGoodCertContext; hr = S_OK; ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return hr; TRACE_ERROR(GetGoodCertContextError); } BOOL CCEnroll::CopyAndPushStackExtension( PCERT_EXTENSION pExt, BOOL fCMC) { DWORD cb = 0; DWORD cbOid = 0; PEXT_STACK pExtStackEle = NULL; PBYTE pb = NULL; PEXT_STACK *ppExtStack = NULL; DWORD *pcExtStack = NULL; assert(pExt != NULL); // allocate the space cbOid = POINTERROUND((DWORD)strlen(pExt->pszObjId) + 1); //ia64 align cb = sizeof(EXT_STACK) + cbOid + pExt->Value.cbData; if(NULL == (pb = (PBYTE) malloc(cb))) { SetLastError(ERROR_OUTOFMEMORY); return(FALSE); } // set my pointers pExtStackEle = (PEXT_STACK) pb; pb += sizeof(EXT_STACK); pExtStackEle->ext.pszObjId = (LPSTR) pb; pb += cbOid; pExtStackEle->ext.Value.pbData = pb; // set the values strcpy(pExtStackEle->ext.pszObjId, pExt->pszObjId); pExtStackEle->ext.fCritical = pExt->fCritical; pExtStackEle->ext.Value.cbData = pExt->Value.cbData; memcpy(pExtStackEle->ext.Value.pbData, pExt->Value.pbData, pExt->Value.cbData); // insert on the list EnterCriticalSection(&m_csXEnroll); ppExtStack = fCMC ? &m_pExtStackNew : &m_pExtStack; pcExtStack = fCMC ? &m_cExtStackNew : &m_cExtStack; pExtStackEle->pNext = *ppExtStack; *ppExtStack = pExtStackEle; (*pcExtStack)++; LeaveCriticalSection(&m_csXEnroll); return(TRUE); } PCERT_EXTENSION CCEnroll::PopStackExtension( BOOL fCMC) { PEXT_STACK pExtStackEle = NULL; PEXT_STACK *ppExtStack = NULL; DWORD *pcExtStack = NULL; EnterCriticalSection(&m_csXEnroll); ppExtStack = fCMC ? &m_pExtStackNew : &m_pExtStack; if(NULL != *ppExtStack) { pExtStackEle = *ppExtStack; *ppExtStack = (*ppExtStack)->pNext; pcExtStack = fCMC ? &m_cExtStackNew : &m_cExtStack; (*pcExtStack)--; } LeaveCriticalSection(&m_csXEnroll); return((PCERT_EXTENSION) pExtStackEle); } DWORD CCEnroll::CountStackExtension(BOOL fCMC) { DWORD cExt = 0; EnterCriticalSection(&m_csXEnroll); cExt = fCMC ? m_cExtStackNew : m_cExtStack; LeaveCriticalSection(&m_csXEnroll); return(cExt); } PCERT_EXTENSION CCEnroll::EnumStackExtension( PCERT_EXTENSION pExtLast, BOOL fCMC) { PEXT_STACK pExtStackEle = (PEXT_STACK)pExtLast; EnterCriticalSection(&m_csXEnroll); if(NULL == pExtStackEle) { pExtStackEle = fCMC ? m_pExtStackNew : m_pExtStack; } else { pExtStackEle = pExtStackEle->pNext; } LeaveCriticalSection(&m_csXEnroll); return((PCERT_EXTENSION) pExtStackEle); } void CCEnroll::FreeAllStackExtension(void) { EnterCriticalSection(&m_csXEnroll); //free cmc extensions while(0 != m_cExtStackNew) { FreeStackExtension(PopStackExtension(TRUE)); } //free old client extensions while(0 != m_cExtStack) { FreeStackExtension(PopStackExtension(FALSE)); } LeaveCriticalSection(&m_csXEnroll); } void CCEnroll::FreeStackExtension(PCERT_EXTENSION pExt) { if(pExt != NULL) free(pExt); } //obselete call for new client HRESULT STDMETHODCALLTYPE CCEnroll::AddExtensionsToRequest( /* [in] */ PCERT_EXTENSIONS pCertExtensions) { HRESULT hr = S_OK; DWORD i = 0; assert(pCertExtensions != NULL); for(i = 0; i < pCertExtensions->cExtension; i++) { //push into old extension stack if(!CopyAndPushStackExtension(&pCertExtensions->rgExtension[i], FALSE)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); break; } } return(hr); } BOOL CCEnroll::CopyAndPushStackAttribute( PCRYPT_ATTRIBUTE pAttr, BOOL fCMC) { DWORD i = 0; DWORD cb = 0; DWORD cbOid = 0; PATTR_STACK pAttrStackEle = NULL; PBYTE pb = NULL; PATTR_STACK *ppAttrStack = NULL; DWORD *pcAttrStack = NULL; assert(pAttr != NULL); // allocate the space cb = sizeof(ATTR_STACK); //make sure aligned for ia64 cbOid = POINTERROUND((DWORD)strlen(pAttr->pszObjId) + 1); cb += cbOid; cb += sizeof(CRYPT_ATTR_BLOB) * pAttr->cValue; for(i=0; icValue; i++) cb += POINTERROUND(pAttr->rgValue[i].cbData); //pointer align if(NULL == (pb = (PBYTE) malloc(cb))) { SetLastError(ERROR_OUTOFMEMORY); return(FALSE); } // set my pointers pAttrStackEle = (PATTR_STACK) pb; pb += sizeof(ATTR_STACK); pAttrStackEle->attr.pszObjId = (LPSTR) pb; pb += cbOid; strcpy(pAttrStackEle->attr.pszObjId, pAttr->pszObjId); pAttrStackEle->attr.cValue = pAttr->cValue; pAttrStackEle->attr.rgValue = (PCRYPT_ATTR_BLOB) pb; pb += sizeof(CRYPT_ATTR_BLOB) * pAttr->cValue; for(i=0; icValue; i++) { pAttrStackEle->attr.rgValue[i].pbData = pb; pAttrStackEle->attr.rgValue[i].cbData = pAttr->rgValue[i].cbData; memcpy(pAttrStackEle->attr.rgValue[i].pbData, pAttr->rgValue[i].pbData, pAttr->rgValue[i].cbData); pb += POINTERROUND(pAttr->rgValue[i].cbData); } assert( pb == ((BYTE *) pAttrStackEle) + cb ); // insert on the list EnterCriticalSection(&m_csXEnroll); ppAttrStack = fCMC ? &m_pAttrStackNew : &m_pAttrStack; pcAttrStack = fCMC ? &m_cAttrStackNew : &m_cAttrStack; pAttrStackEle->pNext = *ppAttrStack; *ppAttrStack = pAttrStackEle; (*pcAttrStack)++; LeaveCriticalSection(&m_csXEnroll); return(TRUE); } PCRYPT_ATTRIBUTE CCEnroll::PopStackAttribute(BOOL fCMC) { PATTR_STACK pAttrStackEle = NULL; PATTR_STACK *ppAttrStack = NULL; DWORD *pcAttrStack = NULL; EnterCriticalSection(&m_csXEnroll); ppAttrStack = fCMC ? &m_pAttrStackNew : &m_pAttrStack; if(NULL != *ppAttrStack) { pAttrStackEle = *ppAttrStack; *ppAttrStack = (*ppAttrStack)->pNext; pcAttrStack = fCMC ? &m_cAttrStackNew : &m_cAttrStack; (*pcAttrStack)--; } LeaveCriticalSection(&m_csXEnroll); return((PCRYPT_ATTRIBUTE) pAttrStackEle); } DWORD CCEnroll::CountStackAttribute(BOOL fCMC) { DWORD cAttr = 0; EnterCriticalSection(&m_csXEnroll); cAttr = fCMC ? m_cAttrStackNew : m_cAttrStack; LeaveCriticalSection(&m_csXEnroll); return(cAttr); } PCRYPT_ATTRIBUTE CCEnroll::EnumStackAttribute( PCRYPT_ATTRIBUTE pAttrLast, BOOL fCMC) { PATTR_STACK pAttrStackEle = (PATTR_STACK) pAttrLast; EnterCriticalSection(&m_csXEnroll); if(NULL == pAttrLast) { pAttrStackEle = fCMC ? m_pAttrStackNew : m_pAttrStack; } else { pAttrStackEle = pAttrStackEle->pNext; } LeaveCriticalSection(&m_csXEnroll); return((PCRYPT_ATTRIBUTE) pAttrStackEle); } void CCEnroll::FreeAllStackAttribute(void) { EnterCriticalSection(&m_csXEnroll); while(0 != m_cAttrStackNew) { FreeStackAttribute(PopStackAttribute(TRUE)); } while(0 != m_cAttrStack) { FreeStackAttribute(PopStackAttribute(FALSE)); } LeaveCriticalSection(&m_csXEnroll); } void CCEnroll::FreeStackAttribute(PCRYPT_ATTRIBUTE pAttr) { if(pAttr != NULL) free(pAttr); } HRESULT STDMETHODCALLTYPE CCEnroll::AddAuthenticatedAttributesToPKCS7Request( /* [in] */ PCRYPT_ATTRIBUTES pAttributes) { HRESULT hr = S_OK; DWORD i; for(i = 0; i < pAttributes->cAttr; i++) { if(!CopyAndPushStackAttribute(&pAttributes->rgAttr[i], FALSE)) { hr = (MY_HRESULT_FROM_WIN32(GetLastError())); break; } //put into cmc stack too if(!CopyAndPushStackAttribute(&pAttributes->rgAttr[i], TRUE)) { hr = (MY_HRESULT_FROM_WIN32(GetLastError())); break; } } return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::CreatePKCS7RequestFromRequest( /* [in] */ PCRYPT_DATA_BLOB pRequest, /* [in] */ PCCERT_CONTEXT pSigningRACertContext, /* [out] */ PCRYPT_DATA_BLOB pPkcs7Blob) { HRESULT hr = S_OK; DWORD errBefore = GetLastError(); CRYPT_SIGN_MESSAGE_PARA signMsgPara; PCCRYPT_OID_INFO pOidInfo = NULL; PCRYPT_ATTRIBUTE pAttrCur = NULL; DWORD i; ALG_ID rgAlg[2]; CRYPT_KEY_PROV_INFO *pKeyProvInfo = NULL; DWORD cb = 0; assert(pSigningRACertContext != NULL); assert(pRequest != NULL); assert(pPkcs7Blob != NULL); memset(&signMsgPara, 0, sizeof(CRYPT_SIGN_MESSAGE_PARA)); memset(pPkcs7Blob, 0, sizeof(CRYPT_DATA_BLOB)); if( !GetCapiHashAndSigAlgId(rgAlg) ) goto ErrorGetCapiHashAndSigAlgId; // find out what the oid is if( (NULL == (pOidInfo = xeCryptFindOIDInfo( CRYPT_OID_INFO_ALGID_KEY, (void *) &rgAlg[0], CRYPT_HASH_ALG_OID_GROUP_ID)) ) ) { SetLastError((DWORD)NTE_BAD_ALGID); goto ErrorCryptFindOIDInfo; } // now add all of the user defined extensions EnterCriticalSection(&m_csXEnroll); signMsgPara.cAuthAttr = CountStackAttribute(m_fNewRequestMethod); signMsgPara.rgAuthAttr = (PCRYPT_ATTRIBUTE)LocalAlloc(LMEM_FIXED, signMsgPara.cAuthAttr * sizeof(CRYPT_ATTRIBUTE)); if( NULL == signMsgPara.rgAuthAttr) { SetLastError(ERROR_OUTOFMEMORY); LeaveCriticalSection(&m_csXEnroll); goto ErrorOutOfMemory; } i = 0; pAttrCur = NULL; while(NULL != (pAttrCur = EnumStackAttribute(pAttrCur, m_fNewRequestMethod)) ) { signMsgPara.rgAuthAttr[i] = *pAttrCur; i++; } LeaveCriticalSection(&m_csXEnroll); signMsgPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA); signMsgPara.dwMsgEncodingType = PKCS_7_ASN_ENCODING; signMsgPara.pSigningCert = pSigningRACertContext; signMsgPara.HashAlgorithm.pszObjId = (char *) pOidInfo->pszOID; signMsgPara.cMsgCert = 1; signMsgPara.rgpMsgCert = &pSigningRACertContext; //get key prov info while (TRUE) { if(!CertGetCertificateContextProperty( pSigningRACertContext, CERT_KEY_PROV_INFO_PROP_ID, pKeyProvInfo, &cb)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertGetCertificateContextPropertyError; } if (NULL != pKeyProvInfo) { //got it, done break; } pKeyProvInfo = (CRYPT_KEY_PROV_INFO*)LocalAlloc(LMEM_FIXED, cb); if (NULL == pKeyProvInfo) { hr = E_OUTOFMEMORY; goto ErrorOutOfMemory; } } if (0x0 != (pKeyProvInfo->dwFlags & CRYPT_SILENT)) { //have to set silent through msg param signMsgPara.dwFlags |= CRYPT_MESSAGE_SILENT_KEYSET_FLAG; } if( !CryptSignMessage( &signMsgPara, FALSE, 1, (const BYTE **) &pRequest->pbData, &pRequest->cbData , NULL, &pPkcs7Blob->cbData) || (pPkcs7Blob->pbData = (BYTE *) MyCoTaskMemAlloc(pPkcs7Blob->cbData)) == NULL || !CryptSignMessage( &signMsgPara, FALSE, 1, (const BYTE **) &pRequest->pbData, &pRequest->cbData , pPkcs7Blob->pbData, &pPkcs7Blob->cbData) ) goto ErrorCryptSignMessage; CommonReturn: if (NULL != pKeyProvInfo) { LocalFree(pKeyProvInfo); } if (NULL != signMsgPara.rgAuthAttr) { LocalFree(signMsgPara.rgAuthAttr); } // don't know if we have an error or not // but I do know the errBefore is set properly SetLastError(errBefore); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); // on error return a NULL if(pPkcs7Blob->pbData != NULL) MyCoTaskMemFree(pPkcs7Blob->pbData); memset(pPkcs7Blob, 0, sizeof(CRYPT_DATA_BLOB)); goto CommonReturn; TRACE_ERROR(ErrorGetCapiHashAndSigAlgId); TRACE_ERROR(ErrorCryptSignMessage); TRACE_ERROR(ErrorCryptFindOIDInfo); TRACE_ERROR(ErrorOutOfMemory); TRACE_ERROR(CertGetCertificateContextPropertyError) } HRESULT STDMETHODCALLTYPE CCEnroll::AddNameValuePairToSignatureWStr( /* [in] */ LPWSTR pwszName, /* [in] */ LPWSTR pwszValue) { HRESULT hr = S_OK; assert(pwszName != NULL && pwszValue != NULL); CRYPT_ENROLLMENT_NAME_VALUE_PAIR nameValuePair = {pwszName, pwszValue}; CRYPT_ATTR_BLOB blobAttr; CRYPT_ATTRIBUTE attr = {szOID_ENROLLMENT_NAME_VALUE_PAIR, 1, &blobAttr}; CRYPT_ATTRIBUTES attrs = {1, &attr}; memset(&blobAttr, 0, sizeof(CRYPT_ATTR_BLOB)); hr = xeEncodeNameValuePair( &nameValuePair, &blobAttr.pbData, &blobAttr.cbData); if (S_OK != hr) { goto error; } hr = AddAuthenticatedAttributesToPKCS7Request(&attrs); error: if (NULL != blobAttr.pbData) { MyCoTaskMemFree(blobAttr.pbData); } return hr; } HRESULT STDMETHODCALLTYPE CCEnroll::AddCertTypeToRequestWStr( LPWSTR szw) { HRESULT hr = S_OK; DWORD errBefore = GetLastError(); CERT_NAME_VALUE nameValue; CERT_EXTENSION ext; CERT_EXTENSIONS exts = {1, &ext}; memset(&ext, 0, sizeof(CERT_EXTENSION)); nameValue.dwValueType = CERT_RDN_BMP_STRING; nameValue.Value.cbData = 0; nameValue.Value.pbData = (PBYTE) szw; ext.pszObjId = szOID_ENROLL_CERTTYPE_EXTENSION; if( !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING, &nameValue, NULL, &ext.Value.cbData ) ) goto ErrorCryptEncodeObject; ext.Value.pbData = (PBYTE)LocalAlloc(LMEM_FIXED, ext.Value.cbData); if(NULL == ext.Value.pbData) { SetLastError(ERROR_OUTOFMEMORY); goto ErrorOutOfMemory; } if( !CryptEncodeObject( CRYPT_ASN_ENCODING, X509_UNICODE_ANY_STRING, &nameValue, ext.Value.pbData, &ext.Value.cbData ) ) goto ErrorCryptEncodeObject; if(S_OK != AddExtensionsToRequest(&exts)) goto ErrorAddExtensionsToRequest; //put cert template extension into CMC stack if(!CopyAndPushStackExtension(&ext, TRUE)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CopyAndPushStackExtensionError; } CommonReturn: if (NULL != ext.Value.pbData) { LocalFree(ext.Value.pbData); } // don't know if we have an error or not // but I do know the errBefore is set properly SetLastError(errBefore); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); goto CommonReturn; TRACE_ERROR(ErrorCryptEncodeObject); TRACE_ERROR(ErrorAddExtensionsToRequest); TRACE_ERROR(ErrorOutOfMemory); TRACE_ERROR(CopyAndPushStackExtensionError); } HRESULT STDMETHODCALLTYPE CCEnroll::AddCertTypeToRequestWStrEx( IN LONG lType, IN LPCWSTR pwszOIDOrName, IN LONG lMajorVersion, IN BOOL fMinorVersion, IN LONG lMinorVersion) { HRESULT hr; LPCSTR lpszStructType; CERT_NAME_VALUE nameValue; CERT_TEMPLATE_EXT Template; VOID *pv; CERT_EXTENSION ext; //free pbData DWORD cb = 0; CHAR *pszOID = NULL; //init ZeroMemory(&ext, sizeof(ext)); ext.fCritical = FALSE; if (NULL == pwszOIDOrName) { hr = E_INVALIDARG; goto InvalidArgError; } switch (lType) { case XECT_EXTENSION_V1: ext.pszObjId = szOID_ENROLL_CERTTYPE_EXTENSION; nameValue.dwValueType = CERT_RDN_BMP_STRING; nameValue.Value.cbData = 0; nameValue.Value.pbData = (BYTE*)pwszOIDOrName; pv = (VOID*)&nameValue; lpszStructType = X509_UNICODE_ANY_STRING; break; case XECT_EXTENSION_V2: ext.pszObjId = szOID_CERTIFICATE_TEMPLATE; //convert wsz OID to ansi while (TRUE) { cb = WideCharToMultiByte( GetACP(), 0, pwszOIDOrName, -1, pszOID, cb, NULL, NULL); if (0 == cb) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto WideCharToMultiByteError; } if (NULL != pszOID) { //done break; } pszOID = (CHAR*)LocalAlloc(LMEM_FIXED, cb); if (NULL == pszOID) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } ZeroMemory(&Template, sizeof(Template)); Template.pszObjId = pszOID; Template.dwMajorVersion = lMajorVersion; Template.fMinorVersion = fMinorVersion; Template.dwMinorVersion = lMinorVersion; pv = (VOID*)&Template; lpszStructType = X509_CERTIFICATE_TEMPLATE; break; default: hr = E_INVALIDARG; goto InvalidArgError; break; } while (TRUE) { if (!CryptEncodeObject( X509_ASN_ENCODING, lpszStructType, pv, ext.Value.pbData, &ext.Value.cbData)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptEncodeObjectError; } if (NULL != ext.Value.pbData) { //done break; } ext.Value.pbData = (BYTE*)LocalAlloc(LMEM_FIXED, ext.Value.cbData); if (NULL == ext.Value.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } //put cert template extension into CMC stack if(!CopyAndPushStackExtension(&ext, TRUE)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CopyAndPushStackExtensionError; } hr = S_OK; ErrorReturn: if (NULL != pszOID) { LocalFree(pszOID); } if (NULL != ext.Value.pbData) { LocalFree(ext.Value.pbData); } return hr; TRACE_ERROR(InvalidArgError) TRACE_ERROR(CopyAndPushStackExtensionError) TRACE_ERROR(OutOfMemoryError) TRACE_ERROR(CryptEncodeObjectError) TRACE_ERROR(WideCharToMultiByteError) } HRESULT STDMETHODCALLTYPE CCEnroll::getProviderTypeWStr( IN LPCWSTR pwszProvName, OUT LONG * plProvType) { HRESULT hr; DWORD i = 0; DWORD cb; DWORD dwProvType; WCHAR *pwszEnumProvName = NULL; if (NULL == pwszProvName) { hr = E_INVALIDARG; goto InvalidArgError; } //init *plProvType = -1; while (TRUE) { while (TRUE) { if (!CryptEnumProvidersU( i, NULL, 0, &dwProvType, pwszEnumProvName, &cb)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); if (MY_HRESULT_FROM_WIN32(NTE_PROV_TYPE_ENTRY_BAD) == hr) { //skip bad one and goto next assert(NULL == pwszEnumProvName); break; //skip this one } //error goto CryptEnumProvidersUError; } if (NULL != pwszEnumProvName) { //get the current csp name break; } pwszEnumProvName = (WCHAR*)LocalAlloc(LMEM_FIXED, cb); if (NULL == pwszEnumProvName) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (NULL != pwszEnumProvName) { if (0 == _wcsicmp(pwszProvName, pwszEnumProvName)) { //found matched name *plProvType = (LONG)dwProvType; break; //out of outer loop } } //not mached, go to next one ++i; if (NULL != pwszEnumProvName) { LocalFree(pwszEnumProvName); pwszEnumProvName = NULL; } } hr = S_OK; ErrorReturn: if (NULL != pwszEnumProvName) { LocalFree(pwszEnumProvName); } return hr; TRACE_ERROR(InvalidArgError) TRACE_ERROR(OutOfMemoryError) TRACE_ERROR(CryptEnumProvidersUError) } HRESULT STDMETHODCALLTYPE CCEnroll::InstallPKCS7Blob( /* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7) { return InstallPKCS7BlobEx(pBlobPKCS7, NULL); } HRESULT CCEnroll::InstallPKCS7BlobEx( /* [in] */ PCRYPT_DATA_BLOB pBlobPKCS7, /* [out] */ LONG *plCertInstalled) { HRESULT hr = S_OK; DWORD errBefore = GetLastError(); HCERTSTORE hStoreMsg = NULL; LPWSTR pwszTitle = NULL; LPWSTR pwszNotSafeAccepting = NULL; EnterCriticalSection(&m_csXEnroll); // Accepting a request is not safe for scripting: pop up a warning dialog if called from script if (0 != m_dwEnabledSafteyOptions) { hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFEACTION, &pwszTitle); if (S_OK != hr) { SetLastError(hr); goto xeLoadRCStringError; } hr = xeLoadRCString(hInstanceXEnroll, IDS_NOTSAFE_ACCEPTING_CERT, &pwszNotSafeAccepting); if (S_OK != hr) { SetLastError(hr); goto xeLoadRCStringError; } if (IDYES != MessageBoxU(NULL, pwszNotSafeAccepting, pwszTitle, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2)) { hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); SetLastError(hr); goto CancelledError; } } if( !MyCryptQueryObject(CERT_QUERY_OBJECT_BLOB, pBlobPKCS7, (CERT_QUERY_CONTENT_FLAG_CERT | CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | CERT_QUERY_CONTENT_FLAG_SERIALIZED_STORE | CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED) , CERT_QUERY_FORMAT_FLAG_ALL, 0, NULL, NULL, NULL, &hStoreMsg, NULL, NULL) ) goto ErrorCryptQueryObject; hr = AddCertsToStores(hStoreMsg, plCertInstalled); //don't treat cancel as error but return the err code if (S_OK != hr && MY_HRESULT_FROM_WIN32(ERROR_CANCELLED) != hr) { goto ErrorAddCertsToStores; } CommonReturn: if(hStoreMsg != NULL) CertCloseStore(hStoreMsg, 0); if (NULL != pwszNotSafeAccepting) LocalFree(pwszNotSafeAccepting); if (NULL != pwszTitle) LocalFree(pwszTitle); // don't know if we have an error or not // but I do know the errBefore is set properly SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); goto CommonReturn; TRACE_ERROR(ErrorCryptQueryObject); TRACE_ERROR(ErrorAddCertsToStores); TRACE_ERROR(CancelledError); TRACE_ERROR(xeLoadRCStringError); } HRESULT STDMETHODCALLTYPE CCEnroll::InstallPKCS7( /* [in] */ BSTR wszPKCS7) { CRYPT_DATA_BLOB blobPKCS7; assert(wszPKCS7 != NULL); // just put into a blob memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB)); blobPKCS7.cbData = SysStringByteLen(wszPKCS7); blobPKCS7.pbData = (PBYTE) wszPKCS7; // install the blob return(InstallPKCS7Blob(&blobPKCS7)); } HRESULT STDMETHODCALLTYPE CCEnroll::InstallPKCS7Ex( /* [in] */ BSTR wszPKCS7, /* [out] */ LONG __RPC_FAR *plCertInstalled) { CRYPT_DATA_BLOB blobPKCS7; assert(wszPKCS7 != NULL); // just put into a blob memset(&blobPKCS7, 0, sizeof(CRYPT_DATA_BLOB)); blobPKCS7.cbData = SysStringByteLen(wszPKCS7); blobPKCS7.pbData = (PBYTE) wszPKCS7; // install the blob return(InstallPKCS7BlobEx(&blobPKCS7, plCertInstalled)); } // this is a scary routine. Put in for louis, use at your own risk. HRESULT STDMETHODCALLTYPE CCEnroll::Reset(void) { HRESULT hr; EnterCriticalSection(&m_csXEnroll); Destruct(); hr = Init(); LeaveCriticalSection(&m_csXEnroll); return hr; } HRESULT STDMETHODCALLTYPE CCEnroll::GetSupportedKeySpec( LONG __RPC_FAR *pdwKeySpec) { DWORD errBefore = GetLastError(); DWORD hr = S_OK; DWORD cb = sizeof(DWORD); SetLastError(ERROR_SUCCESS); assert(pdwKeySpec != NULL); *pdwKeySpec = 0; EnterCriticalSection(&m_csXEnroll); hr = GetVerifyProv(); if (S_OK != hr) { goto GetVerifyProvError; } if( !CryptGetProvParam( m_hVerifyProv, PP_KEYSPEC, (BYTE *) pdwKeySpec, &cb, 0 ) ) goto ErrorCryptGetProvParam; CommonReturn: SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); // We have an error, make sure we set it. errBefore = GetLastError(); goto CommonReturn; TRACE_ERROR(ErrorCryptGetProvParam); TRACE_ERROR(GetVerifyProvError); } HRESULT STDMETHODCALLTYPE CCEnroll::GetKeyLenEx( LONG lSizeSpec, LONG lKeySpec, LONG __RPC_FAR *pdwKeySize) { BOOL fKeyX; BOOL fKeyInc = FALSE; DWORD dwKeySize = 0xFFFFFFFF; DWORD cb; HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); switch (lKeySpec) { case XEKL_KEYSPEC_KEYX: fKeyX = TRUE; break; case XEKL_KEYSPEC_SIG: fKeyX = FALSE; break; default: //invalid parameter hr = E_INVALIDARG; goto InvalidArgError; } switch (lSizeSpec) { case XEKL_KEYSIZE_MIN: case XEKL_KEYSIZE_MAX: case XEKL_KEYSIZE_DEFAULT: break; case XEKL_KEYSIZE_INC: fKeyInc = TRUE; break; default: //invalid parameter hr = E_INVALIDARG; goto InvalidArgError; } if (!fKeyInc) { DWORD dwAlg = (fKeyX ? ALG_CLASS_KEY_EXCHANGE : ALG_CLASS_SIGNATURE); *pdwKeySize = GetKeySizeInfo(lSizeSpec, dwAlg); if(0xFFFFFFFF == *pdwKeySize) { *pdwKeySize = 0; hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetKeySizeInfoError; } } else { if ((fKeyX && (0 != m_dwXhgKeyLenInc)) || (!fKeyX && (0 != m_dwSigKeyLenInc))) { //we got the cached inc size if (fKeyX) { *pdwKeySize = m_dwXhgKeyLenInc; } else { *pdwKeySize = m_dwSigKeyLenInc; } } else { hr = GetVerifyProv(); if (S_OK != hr) { goto GetVerifyProvError; } //init *pdwKeySize = 0; cb = sizeof(dwKeySize); if (!CryptGetProvParam( m_hVerifyProv, fKeyX ? PP_KEYX_KEYSIZE_INC : PP_SIG_KEYSIZE_INC, (BYTE*)&dwKeySize, &cb, 0)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptGetProvParamError; } else { *pdwKeySize = dwKeySize; //cache it if (fKeyX) { m_dwXhgKeyLenInc = dwKeySize; } else { m_dwSigKeyLenInc = dwKeySize; } } } } ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); TRACE_ERROR(GetVerifyProvError); TRACE_ERROR(CryptGetProvParamError) TRACE_ERROR(InvalidArgError) TRACE_ERROR(GetKeySizeInfoError) } HRESULT STDMETHODCALLTYPE CCEnroll::GetKeyLen( BOOL fMin, BOOL fExchange, LONG __RPC_FAR *pdwKeySize) { DWORD hr = S_OK; LONG lKeySizeSpec = (fMin ? XEKL_KEYSIZE_MIN : XEKL_KEYSIZE_MAX); if(fExchange) *pdwKeySize = GetKeySizeInfo(lKeySizeSpec, ALG_CLASS_KEY_EXCHANGE); else *pdwKeySize = GetKeySizeInfo(lKeySizeSpec, ALG_CLASS_SIGNATURE); if(*pdwKeySize == 0xFFFFFFFF) { *pdwKeySize = 0; hr = MY_HRESULT_FROM_WIN32(GetLastError()); } return(hr); } DWORD CCEnroll::GetKeySizeInfo( LONG lKeySizeSpec, DWORD algClass) { DWORD cb = sizeof(PROV_ENUMALGS_EX); HRESULT hr = S_OK; DWORD errBefore = GetLastError(); DWORD dwFlags = CRYPT_FIRST; PROV_ENUMALGS_EX algInfo; DWORD dwKeySize = 0xFFFFFFFF; DWORD err = ERROR_SUCCESS; #ifdef DBG //only accept two flags assert(ALG_CLASS_KEY_EXCHANGE == algClass || ALG_CLASS_SIGNATURE == algClass); #endif //DBG SetLastError(ERROR_SUCCESS); memset(&algInfo, 0, sizeof(algInfo)); EnterCriticalSection(&m_csXEnroll); if ((ALG_CLASS_KEY_EXCHANGE == algClass && 0 != m_dwXhgKeyLenMax) || (ALG_CLASS_SIGNATURE == algClass && 0 != m_dwSigKeyLenMax)) { //got cached sizes, use only KeyLenMax as check #if DBG if (ALG_CLASS_KEY_EXCHANGE == algClass) { assert(0 != m_dwXhgKeyLenMin); assert(0 != m_dwXhgKeyLenDef); } if (ALG_CLASS_SIGNATURE == algClass) { assert(0 != m_dwSigKeyLenMin); assert(0 != m_dwSigKeyLenDef); } #endif //DBG //OK, cached, easy } else { #if DBG if (ALG_CLASS_KEY_EXCHANGE == algClass) { assert(0 == m_dwXhgKeyLenMin); assert(0 == m_dwXhgKeyLenDef); } if (ALG_CLASS_SIGNATURE == algClass) { assert(0 == m_dwSigKeyLenMin); assert(0 == m_dwSigKeyLenDef); } #endif //DBG hr = GetVerifyProv(); if (S_OK != hr) { goto GetVerifyProvError; } while (CryptGetProvParam( m_hVerifyProv, PP_ENUMALGS_EX, (BYTE *) &algInfo, &cb, dwFlags)) { // get rid of CRYPT_FIRST flag dwFlags = 0; if (ALG_CLASS_KEY_EXCHANGE == GET_ALG_CLASS(algInfo.aiAlgid)) { //cache them m_dwXhgKeyLenMax = algInfo.dwMaxLen; m_dwXhgKeyLenMin = algInfo.dwMinLen; m_dwXhgKeyLenDef = algInfo.dwDefaultLen; } else if (ALG_CLASS_SIGNATURE == GET_ALG_CLASS(algInfo.aiAlgid)) { m_dwSigKeyLenMax = algInfo.dwMaxLen; m_dwSigKeyLenMin = algInfo.dwMinLen; m_dwSigKeyLenDef = algInfo.dwDefaultLen; } //see if we cache all sizes through single enum loop if (0 != m_dwXhgKeyLenMax && 0 != m_dwXhgKeyLenMin && 0 != m_dwXhgKeyLenDef && 0 != m_dwSigKeyLenMax && 0 != m_dwSigKeyLenMin && 0 != m_dwSigKeyLenDef) { //looks we cached all break; } } } // if we got here, // either PP_ENUMALGS_EX is not supported by CSP , should return error // or csp doesn't support specified algorithm, should ERROR_NO_MORE_ITEMS err = GetLastError(); if (err != ERROR_SUCCESS) { if (err != ERROR_NO_MORE_ITEMS) { goto ErrorCryptGetProvParam; } // should be ERROR_NO_MORE_ITEMS if ((ALG_CLASS_KEY_EXCHANGE == algClass && 0 != m_dwXhgKeyLenMax) || (ALG_CLASS_SIGNATURE == algClass && 0 != m_dwSigKeyLenMax)) { //we may get here because the csp is signature or exchange only //so we cannot cache both once SetLastError(ERROR_SUCCESS); } else { SetLastError((DWORD)NTE_BAD_ALGID); } } //should have all sizes if(XEKL_KEYSIZE_MIN == lKeySizeSpec) { if (ALG_CLASS_KEY_EXCHANGE == algClass) { dwKeySize = m_dwXhgKeyLenMin; } else { dwKeySize = m_dwSigKeyLenMin; } } else if (XEKL_KEYSIZE_MAX == lKeySizeSpec) { if (ALG_CLASS_KEY_EXCHANGE == algClass) { dwKeySize = m_dwXhgKeyLenMax; } else { dwKeySize = m_dwSigKeyLenMax; } } else if (XEKL_KEYSIZE_DEFAULT == lKeySizeSpec) { if (ALG_CLASS_KEY_EXCHANGE == algClass) { dwKeySize = m_dwXhgKeyLenDef; } else { dwKeySize = m_dwSigKeyLenDef; } } CommonReturn: SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(dwKeySize); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); // We have an error, make sure we set it. errBefore = GetLastError(); goto CommonReturn; TRACE_ERROR(GetVerifyProvError); TRACE_ERROR(ErrorCryptGetProvParam); } HRESULT STDMETHODCALLTYPE CCEnroll::EnumAlgs( /* [in] */ LONG dwIndex, /* [in] */ LONG algMask, /* [out] */ LONG __RPC_FAR *pdwAlgID) { DWORD errBefore = GetLastError(); PROV_ENUMALGS enumAlgs; DWORD cb = sizeof(enumAlgs); LONG i = 0; HRESULT hr = S_OK; DWORD dwFlags; BOOL f1st = TRUE; SetLastError(ERROR_SUCCESS); memset(&enumAlgs, 0, sizeof(enumAlgs)); assert(pdwAlgID != NULL); *pdwAlgID = 0; EnterCriticalSection(&m_csXEnroll); hr = GetVerifyProv(); if (S_OK != hr) { goto GetVerifyProvError; } if (MAXDWORD != m_dwLastAlgIndex && ((DWORD)dwIndex) == m_dwLastAlgIndex + 1) { //continue enum dwFlags = 0; while (f1st || (DWORD)algMask != GET_ALG_CLASS(enumAlgs.aiAlgid)) { if(!CryptGetProvParam( m_hVerifyProv, PP_ENUMALGS, (BYTE*)&enumAlgs, &cb, dwFlags)) { goto ErrorCryptGetProvParam; } f1st = FALSE; } } else { dwFlags = CRYPT_FIRST; for (i = 0; i <= dwIndex; i++) { if(!CryptGetProvParam( m_hVerifyProv, PP_ENUMALGS, (BYTE*)&enumAlgs, &cb, dwFlags)) { goto ErrorCryptGetProvParam; } dwFlags = 0; // if we have not hit something we are counting, do it again if ((DWORD)algMask != GET_ALG_CLASS(enumAlgs.aiAlgid)) { i--; } } } //update cached index m_dwLastAlgIndex = dwIndex; *pdwAlgID = enumAlgs.aiAlgid; CommonReturn: SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); //error, reset index m_dwLastAlgIndex = MAXDWORD; goto CommonReturn; TRACE_ERROR(GetVerifyProvError); TRACE_ERROR(ErrorCryptGetProvParam); } HRESULT STDMETHODCALLTYPE CCEnroll::GetAlgNameWStr( /* [in] */ LONG algID, /* [out] */ LPWSTR __RPC_FAR *ppwsz) { DWORD errBefore = GetLastError(); PROV_ENUMALGS enumAlgs; DWORD cb = sizeof(enumAlgs); HRESULT hr = S_OK; DWORD dwFlags = CRYPT_FIRST; SetLastError(ERROR_SUCCESS); memset(&enumAlgs, 0, sizeof(enumAlgs)); EnterCriticalSection(&m_csXEnroll); hr = GetVerifyProv(); if (S_OK != hr) { goto GetVerifyProvError; } do { if( !CryptGetProvParam( m_hVerifyProv, PP_ENUMALGS, (BYTE *) &enumAlgs, &cb, dwFlags) ) goto ErrorCryptGetProvParam; dwFlags = 0; } while((DWORD)algID != enumAlgs.aiAlgid); if( (*ppwsz = WideFromMB(enumAlgs.szName)) == NULL ) goto ErrorOutOfMem; CommonReturn: SetLastError(errBefore); LeaveCriticalSection(&m_csXEnroll); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); goto CommonReturn; TRACE_ERROR(GetVerifyProvError); TRACE_ERROR(ErrorCryptGetProvParam); TRACE_ERROR(ErrorOutOfMem); } HRESULT STDMETHODCALLTYPE CCEnroll::GetAlgName( /* [in] */ LONG algID, /* [out][retval] */ BSTR __RPC_FAR *pbstr) { DWORD errBefore = GetLastError(); LPWSTR pwsz = NULL; HRESULT hr = S_OK; SetLastError(ERROR_SUCCESS); assert(pbstr != NULL); if((hr = GetAlgNameWStr(algID, &pwsz)) != S_OK) goto ErrorgetAlgNameWStr; if( (*pbstr = SysAllocString(pwsz)) == NULL ) goto ErrorSysAllocString; CommonReturn: if(pwsz != NULL) MyCoTaskMemFree(pwsz); SetLastError(errBefore); return(hr); ErrorReturn: if(GetLastError() == ERROR_SUCCESS) SetLastError((DWORD)E_UNEXPECTED); hr = MY_HRESULT_FROM_WIN32(GetLastError()); // We have an error, make sure we set it. errBefore = GetLastError(); goto CommonReturn; TRACE_ERROR(ErrorgetAlgNameWStr); TRACE_ERROR(ErrorSysAllocString); } HRESULT STDMETHODCALLTYPE CCEnroll::get_ReuseHardwareKeyIfUnableToGenNew( /* [retval][out] */ BOOL __RPC_FAR *fBool) { EnterCriticalSection(&m_csXEnroll); *fBool = m_fReuseHardwareKeyIfUnableToGenNew; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ReuseHardwareKeyIfUnableToGenNew( /* [in] */ BOOL fBool) { EnterCriticalSection(&m_csXEnroll); m_fReuseHardwareKeyIfUnableToGenNew = fBool; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreMy( HCERTSTORE hStore ) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_MyStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_MyStore.wszName != wszMY) MyCoTaskMemFree(m_MyStore.wszName); m_MyStore.wszName = NULL; m_MyStore.hStore = CertDuplicateStore(hStore); } LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreCA( HCERTSTORE hStore ) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_CAStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_CAStore.wszName != wszCA) MyCoTaskMemFree(m_CAStore.wszName); m_CAStore.wszName = NULL; m_CAStore.hStore = CertDuplicateStore(hStore); } LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreROOT( HCERTSTORE hStore ) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_RootStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_RootStore.wszName != wszROOT && m_RootStore.wszName != wszCA) MyCoTaskMemFree(m_RootStore.wszName); m_RootStore.wszName = NULL; m_RootStore.hStore = CertDuplicateStore(hStore); } LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::SetHStoreRequest( HCERTSTORE hStore ) { HRESULT hr = S_OK; EnterCriticalSection(&m_csXEnroll); if(m_RequestStore.hStore != NULL) hr = E_ACCESSDENIED; else { if(m_RequestStore.wszName != wszREQUEST) MyCoTaskMemFree(m_RequestStore.wszName); m_RequestStore.wszName = NULL; m_RequestStore.hStore = CertDuplicateStore(hStore); } LeaveCriticalSection(&m_csXEnroll); return(hr); } HRESULT STDMETHODCALLTYPE CCEnroll::put_LimitExchangeKeyToEncipherment( BOOL fBool ) { EnterCriticalSection(&m_csXEnroll); m_fLimitExchangeKeyToEncipherment = fBool; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::get_LimitExchangeKeyToEncipherment( BOOL * fBool ) { EnterCriticalSection(&m_csXEnroll); *fBool = m_fLimitExchangeKeyToEncipherment; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } HRESULT STDMETHODCALLTYPE CCEnroll::put_EnableSMIMECapabilities( BOOL fSMIME ) { HRESULT hr; EnterCriticalSection(&m_csXEnroll); if (m_fKeySpecSetByClient) { //SMIME is set by the client if (AT_SIGNATURE == m_keyProvInfo.dwKeySpec && fSMIME) { //try to set signature key spec also SMIME hr = XENROLL_E_KEYSPEC_SMIME_MISMATCH; goto MismatchError; } } else { //user didn't set key spec //determine the spec accordingly m_keyProvInfo.dwKeySpec = fSMIME ? AT_KEYEXCHANGE : AT_SIGNATURE; } m_fEnableSMIMECapabilities = fSMIME; m_fSMIMESetByClient = TRUE; hr = S_OK; ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return(hr); TRACE_ERROR(MismatchError) } HRESULT STDMETHODCALLTYPE CCEnroll::get_EnableSMIMECapabilities( BOOL * fBool ) { EnterCriticalSection(&m_csXEnroll); *fBool = m_fEnableSMIMECapabilities; LeaveCriticalSection(&m_csXEnroll); return(S_OK); } //ICEnroll4 HRESULT GetCertificateContextFromBStr( IN BSTR bstrCert, OUT PCCERT_CONTEXT *ppCert) { HRESULT hr; PCCERT_CONTEXT pCert = NULL; BYTE *pbCert = NULL; DWORD cbCert = 0; // could be any form, binary or base64 while (TRUE) { if (!MyCryptStringToBinaryW( (WCHAR*)bstrCert, SysStringLen(bstrCert), CRYPT_STRING_ANY, pbCert, &cbCert, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptStringToBinaryWError; } if (NULL != pbCert) { break; //done } pbCert = (BYTE*)LocalAlloc(LMEM_FIXED, cbCert); if (NULL == pbCert) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } pCert = CertCreateCertificateContext( X509_ASN_ENCODING, pbCert, cbCert); if (NULL == pCert) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertCreateCertificateContextError; } *ppCert = pCert; pCert = NULL; hr = S_OK; ErrorReturn: if (NULL != pbCert) { LocalFree(pbCert); } if (NULL != pCert) { CertFreeCertificateContext(pCert); } return (hr); TRACE_ERROR(CertCreateCertificateContextError) TRACE_ERROR(MyCryptStringToBinaryWError) TRACE_ERROR(OutOfMemoryError) } HRESULT STDMETHODCALLTYPE CCEnroll::put_PrivateKeyArchiveCertificate( IN BSTR bstrCert) { HRESULT hr; PCCERT_CONTEXT pPrivateKeyArchiveCert = NULL; if (NULL != bstrCert) { hr = GetCertificateContextFromBStr(bstrCert, &pPrivateKeyArchiveCert); if (S_OK != hr) { goto GetCertificateContextFromBStrError; } } // set key archive certificate hr = SetPrivateKeyArchiveCertificate(pPrivateKeyArchiveCert); if (S_OK != hr) { goto SetPrivateKeyArchiveCertificateError; } hr = S_OK; ErrorReturn: if (NULL != pPrivateKeyArchiveCert) { CertFreeCertificateContext(pPrivateKeyArchiveCert); } return hr; TRACE_ERROR(GetCertificateContextFromBStrError) TRACE_ERROR(SetPrivateKeyArchiveCertificateError) } HRESULT STDMETHODCALLTYPE CCEnroll::get_PrivateKeyArchiveCertificate( OUT BSTR __RPC_FAR *pbstrCert) { HRESULT hr; PCCERT_CONTEXT pPrivateKeyArchiveCert = NULL; CRYPT_DATA_BLOB blobCert; //init *pbstrCert = NULL; pPrivateKeyArchiveCert = GetPrivateKeyArchiveCertificate(); if (NULL != pPrivateKeyArchiveCert) { blobCert.pbData = pPrivateKeyArchiveCert->pbCertEncoded; blobCert.cbData = pPrivateKeyArchiveCert->cbCertEncoded; hr = BlobToBstring(&blobCert, CRYPT_STRING_BASE64HEADER, pbstrCert); if (S_OK != hr) { goto BlobToBstringError; } } hr = S_OK; ErrorReturn: if (NULL != pPrivateKeyArchiveCert) { CertFreeCertificateContext(pPrivateKeyArchiveCert); } return hr; TRACE_ERROR(BlobToBstringError) } HRESULT STDMETHODCALLTYPE CCEnroll::put_ThumbPrint(IN BSTR bstrThumbPrint) { CRYPT_DATA_BLOB hashBlob; HRESULT hr; if (bstrThumbPrint == NULL) return E_INVALIDARG; hashBlob.cbData = 0; hashBlob.pbData = NULL; if (!MyCryptStringToBinaryW ((WCHAR*)bstrThumbPrint, SysStringLen(bstrThumbPrint), CRYPT_STRING_BASE64, hashBlob.pbData, &hashBlob.cbData, NULL, NULL)) goto MyCryptToBinaryErr; hashBlob.pbData = (LPBYTE)LocalAlloc(LPTR, hashBlob.cbData); if (NULL == hashBlob.pbData) goto MemoryErr; if (!MyCryptStringToBinaryW ((WCHAR*)bstrThumbPrint, SysStringLen(bstrThumbPrint), CRYPT_STRING_BASE64, hashBlob.pbData, &hashBlob.cbData, NULL, NULL)) goto MyCryptToBinaryErr; hr = this->put_ThumbPrintWStr(hashBlob); ErrorReturn: if (NULL != hashBlob.pbData) { LocalFree(hashBlob.pbData); } return hr; SET_HRESULT(MyCryptToBinaryErr, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); } HRESULT STDMETHODCALLTYPE CCEnroll::put_ThumbPrintWStr(IN CRYPT_DATA_BLOB hashBlob) { if (hashBlob.pbData == NULL) return E_INVALIDARG; if (m_hashBlobPendingRequest.pbData != NULL) { LocalFree(m_hashBlobPendingRequest.pbData); m_hashBlobPendingRequest.pbData = NULL; } m_hashBlobPendingRequest.cbData = hashBlob.cbData; m_hashBlobPendingRequest.pbData = (LPBYTE)LocalAlloc(LPTR, m_hashBlobPendingRequest.cbData); if (m_hashBlobPendingRequest.pbData == NULL) return E_OUTOFMEMORY; CopyMemory(m_hashBlobPendingRequest.pbData, hashBlob.pbData, hashBlob.cbData); return S_OK; } HRESULT STDMETHODCALLTYPE CCEnroll::get_ThumbPrint(OUT BSTR __RPC_FAR *pbstrThumbPrint) { CRYPT_DATA_BLOB hashBlob; DWORD cchThumbPrintStr; HRESULT hr; WCHAR *pwszThumbPrint = NULL; int i, n; // Input validation: if (pbstrThumbPrint == NULL) return E_INVALIDARG; // Initialize locals: ZeroMemory(&hashBlob, sizeof(hashBlob)); *pbstrThumbPrint = NULL; if (S_OK != (hr = this->get_ThumbPrintWStr(&hashBlob))) goto ErrorReturn; hashBlob.pbData = (LPBYTE)LocalAlloc(LPTR, hashBlob.cbData); if (NULL == hashBlob.pbData) goto MemoryErr; if (S_OK != (hr = this->get_ThumbPrintWStr(&hashBlob))) goto ErrorReturn; // Now we have a binary thumbprint. Convert this to base64: while (TRUE) { if (!MyCryptBinaryToStringW( hashBlob.pbData, hashBlob.cbData, CRYPT_STRING_BASE64 | CRYPT_STRING_NOCR, pwszThumbPrint, &cchThumbPrintStr)) { goto MyCryptToStringErr; } if (NULL != pwszThumbPrint) { //done break; } pwszThumbPrint = (WCHAR*)LocalAlloc(LMEM_FIXED, cchThumbPrintStr * sizeof(WCHAR)); if (NULL == pwszThumbPrint) { goto MemoryErr; } } //make sure no new line and CR n = (int)wcslen(pwszThumbPrint); for (i = n - 1; i > -1; --i) { if (L'\r' != pwszThumbPrint[i] && L'\n' != pwszThumbPrint[i]) { break; //done } pwszThumbPrint[i] = L'\0'; //null it } // Ok, we've acquired the HASH. Now copy it to the out parameter: *pbstrThumbPrint = SysAllocString(pwszThumbPrint); if (NULL == *pbstrThumbPrint) { goto MemoryErr; } hr = S_OK; ErrorReturn: if (NULL != hashBlob.pbData) { LocalFree(hashBlob.pbData); } if (NULL != pwszThumbPrint) { LocalFree(pwszThumbPrint); } return hr; SET_HRESULT(MyCryptToStringErr, MY_HRESULT_FROM_WIN32(GetLastError())) SET_HRESULT(MemoryErr, E_OUTOFMEMORY) } HRESULT STDMETHODCALLTYPE CCEnroll::get_ThumbPrintWStr(IN OUT PCRYPT_DATA_BLOB pHashBlob) { HRESULT hr = S_OK; // Input validation: if (NULL == pHashBlob) return E_INVALIDARG; // TWO CASES: // // 1) the thumbprint has been explicitly set by an external caller. // 2) the thumbprint _wasn't_ explicitly set. In this case, use the thumbprint // of the request generated by the last call to createPKCS10(). // // CASE 1: // if (NULL != m_hashBlobPendingRequest.pbData) { if (NULL != pHashBlob->pbData) { if (pHashBlob->cbData < m_hashBlobPendingRequest.cbData) { hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA); } else { CopyMemory(pHashBlob->pbData, m_hashBlobPendingRequest.pbData, m_hashBlobPendingRequest.cbData); hr = S_OK; } } pHashBlob->cbData = m_hashBlobPendingRequest.cbData; return hr; } // CASE 2: // else { if (NULL == m_pCertContextPendingRequest) return E_POINTER; // Executes at most twice. if (!CertGetCertificateContextProperty (m_pCertContextPendingRequest, CERT_HASH_PROP_ID, (LPVOID)(pHashBlob->pbData), &(pHashBlob->cbData))) { return MY_HRESULT_FROM_WIN32(GetLastError()); } return S_OK; } } HRESULT STDMETHODCALLTYPE CCEnroll::binaryToString( IN LONG Flags, IN BSTR strBinary, OUT BSTR *pstrEncoded) { HRESULT hr; CRYPT_DATA_BLOB blobBinary; WCHAR *pwszEncoded = NULL; blobBinary.pbData = (BYTE*)strBinary; blobBinary.cbData = SysStringByteLen(strBinary); hr = binaryBlobToString(Flags, &blobBinary, &pwszEncoded); if (S_OK != hr) { goto binaryBlobToStringError; } *pstrEncoded = SysAllocString(pwszEncoded); if (NULL == pstrEncoded) { hr = E_OUTOFMEMORY; goto SysAllocStringLenError; } hr = S_OK; ErrorReturn: if (NULL != pwszEncoded) { MyCoTaskMemFree(pwszEncoded); } return hr; TRACE_ERROR(binaryBlobToStringError); TRACE_ERROR(SysAllocStringLenError); } HRESULT STDMETHODCALLTYPE CCEnroll::stringToBinary( IN LONG Flags, IN BSTR strEncoded, OUT BSTR *pstrBinary) { HRESULT hr; CRYPT_DATA_BLOB blobBinary; ZeroMemory(&blobBinary, sizeof(blobBinary)); hr = stringToBinaryBlob(Flags, (LPCWSTR)strEncoded, &blobBinary, NULL, NULL); if (S_OK != hr) { goto stringToBinaryBlobError; } *pstrBinary = SysAllocStringLen( (OLECHAR*)blobBinary.pbData, blobBinary.cbData); if (NULL == *pstrBinary) { hr = E_OUTOFMEMORY; goto SysAllocStringLenError; } hr = S_OK; ErrorReturn: if (NULL != blobBinary.pbData) { MyCoTaskMemFree(blobBinary.pbData); } return hr; TRACE_ERROR(stringToBinaryBlobError); TRACE_ERROR(SysAllocStringLenError); } HRESULT STDMETHODCALLTYPE CCEnroll::addExtensionToRequest( IN LONG Flags, IN BSTR strName, IN BSTR strValue) { HRESULT hr; CRYPT_DATA_BLOB blobValue; DWORD cchStrValue = SysStringLen(strValue); BYTE *pbExtVal = NULL; DWORD cbExtVal = 0; //convert to binary in case base64 etc. while (TRUE) { if (!MyCryptStringToBinaryW( (WCHAR*)strValue, cchStrValue, CRYPT_STRING_ANY, pbExtVal, &cbExtVal, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptStringToBinaryWError; } if (NULL != pbExtVal) { //done break; } pbExtVal = (BYTE*)LocalAlloc(LMEM_FIXED, cbExtVal); if (NULL == pbExtVal) { hr = E_OUTOFMEMORY; goto LocalAllocError; } } blobValue.pbData = pbExtVal; blobValue.cbData = cbExtVal; hr = addExtensionToRequestWStr(Flags, strName, &blobValue); if (S_OK != hr) { goto addExtensionToRequestWStrError; } hr = S_OK; ErrorReturn: if (NULL != pbExtVal) { LocalFree(pbExtVal); } return hr; TRACE_ERROR(MyCryptStringToBinaryWError) TRACE_ERROR(LocalAllocError) TRACE_ERROR(addExtensionToRequestWStrError) } HRESULT STDMETHODCALLTYPE CCEnroll::addAttributeToRequest( IN LONG Flags, IN BSTR strName, IN BSTR strValue) { HRESULT hr; CRYPT_DATA_BLOB blobValue; DWORD cchStrValue = SysStringLen(strValue); BYTE *pbAttVal = NULL; DWORD cbAttVal = 0; //convert to binary in case base64 etc. while (TRUE) { if (!MyCryptStringToBinaryW( (WCHAR*)strValue, cchStrValue, CRYPT_STRING_ANY, pbAttVal, &cbAttVal, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptStringToBinaryWError; } if (NULL != pbAttVal) { //done break; } pbAttVal = (BYTE*)LocalAlloc(LMEM_FIXED, cbAttVal); if (NULL == pbAttVal) { hr = E_OUTOFMEMORY; goto LocalAllocError; } } blobValue.pbData = pbAttVal; blobValue.cbData = cbAttVal; hr = addAttributeToRequestWStr(Flags, strName, &blobValue); if (S_OK != hr) { goto addAttributeToRequestWStrError; } hr = S_OK; ErrorReturn: if (NULL != pbAttVal) { LocalFree(pbAttVal); } return hr; TRACE_ERROR(MyCryptStringToBinaryWError) TRACE_ERROR(LocalAllocError) TRACE_ERROR(addAttributeToRequestWStrError) } HRESULT STDMETHODCALLTYPE CCEnroll::addNameValuePairToRequest( IN LONG Flags, //not used IN BSTR strName, IN BSTR strValue) { return addNameValuePairToRequestWStr(Flags, strName, strValue); } HRESULT STDMETHODCALLTYPE CCEnroll::addBlobPropertyToCertificate( IN LONG lPropertyId, IN LONG lFlags, IN BSTR strProperty) { CRYPT_DATA_BLOB blob; blob.pbData = (BYTE*)strProperty; blob.cbData = SysStringByteLen(strProperty); if (0x0 != (XECP_STRING_PROPERTY & lFlags)) { //this is a string property, including null blob.cbData += sizeof(WCHAR); } return addBlobPropertyToCertificateWStr(lPropertyId, lFlags, &blob); } HRESULT STDMETHODCALLTYPE CCEnroll::put_SignerCertificate( IN BSTR bstrCert) { HRESULT hr; PCCERT_CONTEXT pSignerCert = NULL; if (NULL != bstrCert) { hr = GetCertificateContextFromBStr(bstrCert, &pSignerCert); if (S_OK != hr) { goto GetCertificateContextFromBStrError; } } // set key archive certificate hr = SetSignerCertificate(pSignerCert); if (S_OK != hr) { goto SetSignerCertificateError; } hr = S_OK; ErrorReturn: if (NULL != pSignerCert) { CertFreeCertificateContext(pSignerCert); } return hr; TRACE_ERROR(GetCertificateContextFromBStrError) TRACE_ERROR(SetSignerCertificateError) } HRESULT STDMETHODCALLTYPE CCEnroll::resetExtensions() { HRESULT hr = S_OK; FreeAllStackExtension(); return hr; } HRESULT STDMETHODCALLTYPE CCEnroll::resetAttributes() { HRESULT hr = S_OK; FreeAllStackAttribute(); return hr; } HRESULT STDMETHODCALLTYPE CCEnroll::createRequest( IN LONG Flags, IN BSTR strDNName, IN BSTR strUsage, OUT BSTR *pstrRequest) { return createRequestWStrBStr( Flags, (LPCWSTR)strDNName, (LPCWSTR)strUsage, CRYPT_STRING_BASE64REQUESTHEADER, pstrRequest); } HRESULT STDMETHODCALLTYPE CCEnroll::createFileRequest( IN LONG Flags, IN BSTR strDNName, IN BSTR strUsage, IN BSTR strRequestFileName) { return createFileRequestWStr(Flags, (LPCWSTR)strDNName, (LPCWSTR)strUsage, (LPCWSTR)strRequestFileName); } HRESULT STDMETHODCALLTYPE CCEnroll::acceptResponse( IN BSTR bstrResponse) { HRESULT hr; CRYPT_DATA_BLOB blobResponse; DWORD cchStrResponse; ZeroMemory(&blobResponse, sizeof(blobResponse)); if (NULL == bstrResponse) { hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto InvalidParameterError; } //assume a string cchStrResponse = SysStringLen(bstrResponse); //convert to binary in case base64 etc. while (TRUE) { if (!MyCryptStringToBinaryW( (WCHAR*)bstrResponse, cchStrResponse, CRYPT_STRING_ANY, blobResponse.pbData, &blobResponse.cbData, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptStringToBinaryWError; } if (NULL != blobResponse.pbData) { //done break; } blobResponse.pbData = (BYTE*)LocalAlloc( LMEM_FIXED, blobResponse.cbData); if (NULL == blobResponse.pbData) { hr = E_OUTOFMEMORY; goto LocalAllocError; } } // accept the blob hr = acceptResponseBlob(&blobResponse); if (S_OK != hr) { goto acceptResponseBlobError; } hr = S_OK; ErrorReturn: if (NULL != blobResponse.pbData) { LocalFree(blobResponse.pbData); } return (hr); TRACE_ERROR(acceptResponseBlobError) TRACE_ERROR(InvalidParameterError) TRACE_ERROR(MyCryptStringToBinaryWError) TRACE_ERROR(LocalAllocError) } HRESULT STDMETHODCALLTYPE CCEnroll::acceptFileResponse( IN BSTR bstrResponseFileName) { return acceptFileResponseWStr((LPCWSTR)bstrResponseFileName); } HRESULT CCEnroll::GetCertFromResponseBlobToBStr( IN CRYPT_DATA_BLOB *pBlobResponse, OUT BSTR *pstrCert) { HRESULT hr; CRYPT_DATA_BLOB blobCert; PCCERT_CONTEXT pCert = NULL; hr = getCertContextFromResponseBlob( pBlobResponse, &pCert); if (S_OK != hr) { goto getCertContextFromResponseBlobError; } assert(NULL != pCert); blobCert.pbData = pCert->pbCertEncoded; blobCert.cbData = pCert->cbCertEncoded; hr = BlobToBstring(&blobCert, CRYPT_STRING_BASE64HEADER, pstrCert); if (S_OK != hr) { goto BlobToBstringError; } hr = S_OK; ErrorReturn: if (NULL != pCert) { CertFreeCertificateContext(pCert); } return hr; TRACE_ERROR(getCertContextFromResponseBlobError) TRACE_ERROR(BlobToBstringError) } HRESULT STDMETHODCALLTYPE CCEnroll::getCertFromResponse( IN BSTR strResponse, OUT BSTR *pstrCert) { HRESULT hr; CRYPT_DATA_BLOB blobResponse; ZeroMemory(&blobResponse, sizeof(blobResponse)); if (NULL == strResponse) { hr = E_POINTER; goto NullPointerError; } hr = BstringToBlob(strResponse, &blobResponse); if (S_OK != hr) { goto BstringToBlobError; } hr = GetCertFromResponseBlobToBStr( &blobResponse, pstrCert); if (S_OK != hr) { goto GetCertFromResponseBlobToBStrError; } hr = S_OK; ErrorReturn: return hr; TRACE_ERROR(NullPointerError) TRACE_ERROR(BstringToBlobError) TRACE_ERROR(GetCertFromResponseBlobToBStrError) } HRESULT STDMETHODCALLTYPE CCEnroll::getCertFromFileResponse( IN BSTR strResponseFileName, OUT BSTR *pstrCert) { HRESULT hr; CRYPT_DATA_BLOB blobResponse; ZeroMemory(&blobResponse, sizeof(blobResponse)); hr = xeStringToBinaryFromFile( (LPCWSTR)strResponseFileName, &blobResponse.pbData, &blobResponse.cbData, CRYPT_STRING_ANY); if (S_OK != hr) { goto xeStringToBinaryFromFileError; } hr = GetCertFromResponseBlobToBStr( &blobResponse, pstrCert); if (S_OK != hr) { goto GetCertFromResponseBlobToBStrError; } hr = S_OK; ErrorReturn: if (NULL != blobResponse.pbData) { LocalFree(blobResponse.pbData); } return hr; TRACE_ERROR(xeStringToBinaryFromFileError) TRACE_ERROR(GetCertFromResponseBlobToBStrError) } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::createPFX( IN BSTR strPassword, OUT BSTR *pstrPFX) { if (0 != m_dwEnabledSafteyOptions) // not safe for scripting return E_ACCESSDENIED; return createPFXWStrBStr((LPCWSTR)strPassword, pstrPFX); } HRESULT STDMETHODCALLTYPE CCEnroll::createFilePFX( IN BSTR strPassword, IN BSTR strPFXFileName) { return createFilePFXWStr((LPCWSTR)strPassword, (LPCWSTR)strPFXFileName); } HRESULT STDMETHODCALLTYPE CCEnroll::setPendingRequestInfo( IN LONG lRequestID, IN BSTR strCADNS, IN BSTR strCAName, IN BSTR strFriendlyName ) { return setPendingRequestInfoWStr( lRequestID, (LPCWSTR)strCADNS, (LPCWSTR)strCAName, (LPCWSTR)strFriendlyName); } HRESULT STDMETHODCALLTYPE CCEnroll::enumPendingRequest( IN LONG lIndex, IN LONG lDesiredProperty, OUT VARIANT *pvarProperty ) { CRYPT_DATA_BLOB dataBlobProperty; HRESULT hr; LONG lProperty; VARIANT varProperty; // See if we're initializing an enumeration. If so, just dispatch to // enumPendingRequestWStr: if (XEPR_ENUM_FIRST == lIndex) { return enumPendingRequestWStr(XEPR_ENUM_FIRST, 0, NULL); } // Input validation: if (lIndex < 0 || NULL == pvarProperty) return E_INVALIDARG; // Initialize locals: memset(&varProperty, 0, sizeof(VARIANT)); memset(&dataBlobProperty, 0, sizeof(CRYPT_DATA_BLOB)); switch (lDesiredProperty) { case XEPR_REQUESTID: case XEPR_VERSION: if (S_OK != (hr = enumPendingRequestWStr(lIndex, lDesiredProperty, &lProperty))) goto ErrorReturn; varProperty.vt = VT_I4; varProperty.lVal = lProperty; *pvarProperty = varProperty; goto CommonReturn; case XEPR_CANAME: case XEPR_CAFRIENDLYNAME: case XEPR_CADNS: case XEPR_HASH: case XEPR_V1TEMPLATENAME: case XEPR_V2TEMPLATEOID: dataBlobProperty.cbData = 0; dataBlobProperty.pbData = NULL; // Determine the size of the property we desire. hr = enumPendingRequestWStr(lIndex, lDesiredProperty, (LPVOID)&dataBlobProperty); if (S_OK != hr || 0 == dataBlobProperty.cbData) goto ErrorReturn; dataBlobProperty.pbData = (LPBYTE)LocalAlloc(LPTR, dataBlobProperty.cbData); if (NULL == dataBlobProperty.pbData) goto MemoryErr; // Request the property, using our newly allocated buffer. hr = enumPendingRequestWStr(lIndex, lDesiredProperty, (LPVOID)&dataBlobProperty); if (hr != S_OK) goto ErrorReturn; varProperty.vt = VT_BSTR; varProperty.bstrVal = SysAllocStringByteLen((LPCSTR)dataBlobProperty.pbData, dataBlobProperty.cbData); if (NULL == varProperty.bstrVal) goto MemoryErr; *pvarProperty = varProperty; goto CommonReturn; case XEPR_DATE: goto NotImplErr; default: goto InvalidArgErr; } CommonReturn: if (NULL != dataBlobProperty.pbData) { LocalFree(dataBlobProperty.pbData); } return hr; ErrorReturn: if (NULL != varProperty.bstrVal) { SysFreeString(varProperty.bstrVal); } goto CommonReturn; SET_HRESULT(InvalidArgErr, E_INVALIDARG); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); SET_HRESULT(NotImplErr, E_NOTIMPL); } HRESULT STDMETHODCALLTYPE CCEnroll::removePendingRequest( IN BSTR bstrThumbPrint ) { CRYPT_DATA_BLOB hashBlob; HRESULT hr; if (bstrThumbPrint == NULL) return E_INVALIDARG; hashBlob.cbData = 0; hashBlob.pbData = NULL; if (!MyCryptStringToBinaryW ((WCHAR*)bstrThumbPrint, SysStringLen(bstrThumbPrint), CRYPT_STRING_ANY, hashBlob.pbData, &hashBlob.cbData, NULL, NULL)) goto MyCryptToBinaryErr; hashBlob.pbData = (LPBYTE)LocalAlloc(LPTR, hashBlob.cbData); if (NULL == hashBlob.pbData) goto MemoryErr; if (!MyCryptStringToBinaryW ((WCHAR*)bstrThumbPrint, SysStringLen(bstrThumbPrint), CRYPT_STRING_ANY, hashBlob.pbData, &hashBlob.cbData, NULL, NULL)) goto MyCryptToBinaryErr; hr = this->removePendingRequestWStr(hashBlob); CommonReturn: if (NULL != hashBlob.pbData) { LocalFree(hashBlob.pbData); } return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(MyCryptToBinaryErr, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); } //IEnroll4 HRESULT myCertGetNameString( IN PCCERT_CONTEXT pCert, IN BOOL fIssuer, OUT WCHAR **ppwszName) { HRESULT hr; DWORD dwFlags = fIssuer ? CERT_NAME_ISSUER_FLAG : 0; DWORD dwTypePara; WCHAR *pwszName = NULL; DWORD cch = 0; while (TRUE) { cch = CertGetNameStringW( pCert, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, (void*)&dwTypePara, pwszName, cch); if (0 == cch) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertGetNameStringError; } if (NULL != pwszName) { //done break; } pwszName = (WCHAR*)LocalAlloc(LMEM_FIXED, cch * sizeof(WCHAR)); if (NULL == pwszName) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } *ppwszName = pwszName; pwszName = NULL; hr = S_OK; ErrorReturn: if (NULL != pwszName) { LocalFree(pwszName); } return hr; TRACE_ERROR(CertGetNameStringError) TRACE_ERROR(OutOfMemoryError) } HRESULT CCEnroll::GetGoodCertContext( IN PCCERT_CONTEXT pCertContext, OUT PCCERT_CONTEXT *ppGoodCertContext) { HRESULT hr; PCCERT_CONTEXT pGoodCertContext = NULL; DWORD cb; //init *ppGoodCertContext = NULL; if(pCertContext == NULL) { hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto InvalidParameterError; } //see if the passed cert has kpi if(CertGetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &cb)) { //this means kpi exists, passed cert is good pGoodCertContext = CertDuplicateCertificateContext(pCertContext); if (NULL == pGoodCertContext) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertDuplicateCertificateContextError; } } *ppGoodCertContext = pGoodCertContext; pGoodCertContext = NULL; hr = S_OK; ErrorReturn: if (NULL != pGoodCertContext) { CertFreeCertificateContext(pGoodCertContext); } return hr; TRACE_ERROR(InvalidParameterError) TRACE_ERROR(CertDuplicateCertificateContextError) } HRESULT STDMETHODCALLTYPE CCEnroll::SetSignerCertificate( IN PCCERT_CONTEXT pCertContext) { HRESULT hr; PCCERT_CONTEXT pCertGoodContext = NULL; EnterCriticalSection(&m_csXEnroll); hr = GetGoodCertContext(pCertContext, &pCertGoodContext); if (S_OK != hr) { goto GetGoodCertContextError; } if(NULL != m_pCertContextSigner) { CertFreeCertificateContext(m_pCertContextSigner); } m_pCertContextSigner = pCertGoodContext; hr = S_OK; ErrorReturn: LeaveCriticalSection(&m_csXEnroll); return hr; TRACE_ERROR(GetGoodCertContextError) } HRESULT VerifyPrivateKeyArchiveCertificate( IN PCCERT_CONTEXT pCert) { HRESULT hr; CERT_CHAIN_PARA ChainParams; CERT_CHAIN_POLICY_PARA ChainPolicy; CERT_CHAIN_POLICY_STATUS PolicyStatus; CERT_CHAIN_CONTEXT const *pCertChain = NULL; char *apszCAXchgOids[] = {szOID_KP_CA_EXCHANGE}; WCHAR *pwszSubject = NULL; WCHAR *pwszIssuer = NULL; WCHAR *pwszDesignedSubject = NULL; //easy check to make sure ca exchange cert issuer and subject //names are in convention hr = myCertGetNameString( pCert, FALSE, &pwszSubject); if (S_OK != hr) { goto myCertGetNameStringError; } hr = myCertGetNameString( pCert, TRUE, &pwszIssuer); if (S_OK != hr) { goto myCertGetNameStringError; } hr = myAddNameSuffix( pwszIssuer, wszCNXCHGSUFFIX, cchCOMMONNAMEMAX_XELIB, &pwszDesignedSubject); if (S_OK != hr) { goto myAddNameSuffixError; } if (0 != wcscmp(pwszSubject, pwszDesignedSubject)) { //unexpected, they should match hr = E_INVALIDARG; goto InvalidArgError; } ZeroMemory(&ChainParams, sizeof(ChainParams)); ChainParams.cbSize = sizeof(ChainParams); ChainParams.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND; ChainParams.RequestedUsage.Usage.rgpszUsageIdentifier = apszCAXchgOids; ChainParams.RequestedUsage.Usage.cUsageIdentifier = ARRAYSIZE(apszCAXchgOids); //get cert chain 1st if (!MyCertGetCertificateChain( NULL, //HHCE_CURRENT_USER pCert, //ca exchange cert NULL, //use current system time NULL, //no additional stores &ChainParams, //chain params CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT, // Make sure that none of the certs in the chain were revoked NULL, //reserved &pCertChain)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertGetCertificateChainError; } ZeroMemory(&ChainPolicy, sizeof(ChainPolicy)); ChainPolicy.cbSize = sizeof(ChainPolicy); ChainPolicy.dwFlags = CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG; ZeroMemory(&PolicyStatus, sizeof(PolicyStatus)); PolicyStatus.cbSize = sizeof(PolicyStatus); PolicyStatus.lChainIndex = -1; PolicyStatus.lElementIndex = -1; //verify the chain if (!MyCertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_BASE, pCertChain, &ChainPolicy, &PolicyStatus)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertVerifyCertificateChainPolicyError; } if (S_OK != PolicyStatus.dwError) { //chain back to root fails hr = PolicyStatus.dwError; goto CertVerifyCertificateChainPolicyError; } hr = S_OK; ErrorReturn: if (NULL != pCertChain) { MyCertFreeCertificateChain(pCertChain); } if (NULL != pwszSubject) { LocalFree(pwszSubject); } if (NULL != pwszDesignedSubject) { LocalFree(pwszDesignedSubject); } if (NULL != pwszIssuer) { LocalFree(pwszIssuer); } return hr; TRACE_ERROR(CertGetCertificateChainError) TRACE_ERROR(CertVerifyCertificateChainPolicyError) TRACE_ERROR(InvalidArgError) TRACE_ERROR(myCertGetNameStringError) TRACE_ERROR(myAddNameSuffixError) } HRESULT STDMETHODCALLTYPE CCEnroll::SetPrivateKeyArchiveCertificate( IN PCCERT_CONTEXT pPrivateKeyArchiveCert) { HRESULT hr; PCCERT_CONTEXT pCert = NULL; if (NULL != pPrivateKeyArchiveCert) { //duplicate the cert pCert = CertDuplicateCertificateContext(pPrivateKeyArchiveCert); if (NULL == pCert) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertDuplicateCertificateContextError; } //verify ca exchange cert hr = VerifyPrivateKeyArchiveCertificate(pCert); if (S_OK != hr) { goto VerifyPrivateKeyArchiveCertificateError; } } EnterCriticalSection(&m_csXEnroll); if (NULL != m_PrivateKeyArchiveCertificate) { CertFreeCertificateContext(m_PrivateKeyArchiveCertificate); } m_PrivateKeyArchiveCertificate = pCert; pCert = NULL; LeaveCriticalSection(&m_csXEnroll); hr = S_OK; ErrorReturn: if (NULL != pCert) { CertFreeCertificateContext(pCert); } return (hr); TRACE_ERROR(CertDuplicateCertificateContextError) TRACE_ERROR(VerifyPrivateKeyArchiveCertificateError) } PCCERT_CONTEXT STDMETHODCALLTYPE CCEnroll::GetPrivateKeyArchiveCertificate(void) { PCCERT_CONTEXT pCert = NULL; EnterCriticalSection(&m_csXEnroll); if (NULL != m_PrivateKeyArchiveCertificate) { pCert = CertDuplicateCertificateContext(m_PrivateKeyArchiveCertificate); } LeaveCriticalSection(&m_csXEnroll); return pCert; } HRESULT STDMETHODCALLTYPE CCEnroll::binaryBlobToString( IN LONG Flags, IN PCRYPT_DATA_BLOB pblobBinary, OUT LPWSTR *ppwszString) { HRESULT hr; WCHAR *pwszEncoded = NULL; DWORD dwEncoded = 0; while (TRUE) { if (!MyCryptBinaryToStringW( pblobBinary->pbData, pblobBinary->cbData, Flags, pwszEncoded, &dwEncoded)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptBinaryToStringError; } if (NULL != pwszEncoded) { //done break; } //dwEncoded includes null terminator pwszEncoded = (WCHAR*)MyCoTaskMemAlloc(dwEncoded * sizeof(WCHAR)); if (NULL == pwszEncoded) { hr = E_OUTOFMEMORY; goto MyCoTaskMemAllocError; } } *ppwszString = pwszEncoded; pwszEncoded = NULL; hr = S_OK; ErrorReturn: if (NULL != pwszEncoded) { MyCoTaskMemFree(pwszEncoded); } return hr; TRACE_ERROR(MyCoTaskMemAllocError) TRACE_ERROR(MyCryptBinaryToStringError) } HRESULT STDMETHODCALLTYPE CCEnroll::stringToBinaryBlob( IN LONG Flags, IN LPCWSTR pwszString, OUT PCRYPT_DATA_BLOB pblobBinary, OUT LONG *pdwSkip, OUT LONG *pdwFlags) { HRESULT hr; size_t nLength = wcslen(pwszString); if (nLength*sizeof(WCHAR) > (DWORD)-1) goto InvalidArgError; //init pblobBinary->pbData = NULL; pblobBinary->cbData = 0; while (TRUE) { if (!MyCryptStringToBinaryW( pwszString, (DWORD)nLength, Flags, pblobBinary->pbData, &pblobBinary->cbData, (DWORD*)pdwSkip, (DWORD*)pdwFlags)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptStringToBinaryWError; } if (NULL != pblobBinary->pbData) { //done break; } pblobBinary->pbData = (BYTE*)MyCoTaskMemAlloc(pblobBinary->cbData); if (NULL == pblobBinary->pbData) { hr = E_OUTOFMEMORY; goto MyCoTaskMemAllocError; } } hr = S_OK; ErrorReturn: return hr; SET_HRESULT(InvalidArgError, E_INVALIDARG); TRACE_ERROR(MyCryptStringToBinaryWError) TRACE_ERROR(MyCoTaskMemAllocError) } HRESULT STDMETHODCALLTYPE CCEnroll::addExtensionToRequestWStr( IN LONG Flags, IN LPCWSTR pwszName, IN PCRYPT_DATA_BLOB pblobValue) { HRESULT hr = S_OK; CERT_EXTENSION ext; CERT_EXTENSION *pExt = NULL; //enum 1st CHAR *pszName = NULL; //convert wsz oid to sz oid hr = xeWSZToSZ(pwszName, &pszName); if (S_OK != hr) { goto error; } while (NULL != (pExt = EnumStackExtension(pExt, TRUE))) { if (0 == strcmp(pszName, pExt->pszObjId)) { //already had the extension, can't have more than 1 hr = MY_HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); goto error; } } //check to see if it is key usage extension if (0 == strcmp(pszName, szOID_KEY_USAGE)) { EnterCriticalSection(&m_csXEnroll); m_fUseClientKeyUsage = TRUE; LeaveCriticalSection(&m_csXEnroll); } ZeroMemory(&ext, sizeof(ext)); ext.fCritical = Flags; ext.pszObjId = pszName; ext.Value = *pblobValue; if(!CopyAndPushStackExtension(&ext, TRUE)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); } error: if (NULL != pszName) { MyCoTaskMemFree(pszName); } return hr; } HRESULT STDMETHODCALLTYPE CCEnroll::addAttributeToRequestWStr( IN LONG /*Flags*/, IN LPCWSTR pwszName, IN PCRYPT_DATA_BLOB pblobValue) { HRESULT hr = S_OK; CRYPT_ATTR_BLOB attrBlob; CRYPT_ATTRIBUTE attr; CHAR *pszName = NULL; //convert wsz oid to sz oid hr = xeWSZToSZ(pwszName, &pszName); if (S_OK != hr) { goto error; } ZeroMemory(&attr, sizeof(attr)); attrBlob = *pblobValue; attr.pszObjId = pszName; attr.cValue = 1; attr.rgValue = &attrBlob; if(!CopyAndPushStackAttribute(&attr, TRUE)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); } error: if (NULL != pszName) { MyCoTaskMemFree(pszName); } return hr; } HRESULT STDMETHODCALLTYPE CCEnroll::addNameValuePairToRequestWStr( IN LONG /*Flags*/, IN LPCWSTR pwszName, IN LPCWSTR pwszValue) { HRESULT hr = S_OK; assert(pwszName != NULL && pwszValue != NULL); CRYPT_ENROLLMENT_NAME_VALUE_PAIR nameValuePair = {const_cast(pwszName), const_cast(pwszValue)}; CRYPT_ATTR_BLOB blobAttr; CRYPT_ATTRIBUTE attr = {szOID_ENROLLMENT_NAME_VALUE_PAIR, 1, &blobAttr}; memset(&blobAttr, 0, sizeof(CRYPT_ATTR_BLOB)); hr = xeEncodeNameValuePair( &nameValuePair, &blobAttr.pbData, &blobAttr.cbData); if (S_OK != hr) { goto error; } if(!CopyAndPushStackAttribute(&attr, TRUE)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); } error: if (NULL != blobAttr.pbData) { MyCoTaskMemFree(blobAttr.pbData); } return hr; } HRESULT STDMETHODCALLTYPE CCEnroll::addBlobPropertyToCertificateWStr( IN LONG lPropertyId, IN LONG lFlags, IN PCRYPT_DATA_BLOB pBlobProp) { HRESULT hr; PPROP_STACK pProp; PPROP_STACK pPropEle = NULL; EnterCriticalSection(&m_csXEnroll); if (NULL == pBlobProp || NULL == pBlobProp->pbData || 0 == pBlobProp->cbData) { hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto InvalidParameterError; } // Don't allow arbitrary properties to be set on the request from a script // (could be a security risk, we should only allow a small set) if (0 != m_dwEnabledSafteyOptions && !IsDesiredProperty(lPropertyId)) { hr = MY_HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER); goto InvalidParameterError; } //check if the same property exists pProp = EnumStackProperty(NULL); while (NULL != pProp) { if (pProp->lPropId == lPropertyId) { //exists already hr = MY_HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); goto PropertyExistError; } pProp = EnumStackProperty(pProp); } pPropEle = (PPROP_STACK)LocalAlloc(LMEM_ZEROINIT, sizeof(PROP_STACK)); if (NULL == pPropEle) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } pPropEle->lPropId = lPropertyId; pPropEle->lFlags = lFlags; pPropEle->prop.pbData = (BYTE*)LocalAlloc(LMEM_FIXED, pBlobProp->cbData); if (NULL == pPropEle->prop.pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } CopyMemory(pPropEle->prop.pbData, pBlobProp->pbData, pBlobProp->cbData); pPropEle->prop.cbData = pBlobProp->cbData; //put into stack pPropEle->pNext = m_pPropStack; m_pPropStack = pPropEle; //assign m_pPropStack m_cPropStack++; //increment of m_cPropStack pPropEle = NULL; hr = S_OK; ErrorReturn: if (NULL != pPropEle) { if (NULL != pPropEle->prop.pbData) { LocalFree(pPropEle->prop.pbData); } LocalFree(pPropEle); } LeaveCriticalSection(&m_csXEnroll); return hr; TRACE_ERROR(InvalidParameterError) TRACE_ERROR(PropertyExistError) TRACE_ERROR(OutOfMemoryError) } PPROP_STACK CCEnroll::EnumStackProperty(PPROP_STACK pProp) { EnterCriticalSection(&m_csXEnroll); if(NULL == pProp) { //1st one pProp = m_pPropStack; } else { pProp = pProp->pNext; } LeaveCriticalSection(&m_csXEnroll); return pProp; } HRESULT STDMETHODCALLTYPE CCEnroll::resetBlobProperties() { PPROP_STACK pPropEle; PPROP_STACK pPropNext; EnterCriticalSection(&m_csXEnroll); pPropEle = m_pPropStack; while (NULL != pPropEle) { //save it to temp pPropNext = EnumStackProperty(pPropEle); //free the current ele if (NULL != pPropEle->prop.pbData) { LocalFree(pPropEle->prop.pbData); } LocalFree(pPropEle); pPropEle = pPropNext; } m_pPropStack = NULL; m_cPropStack = 0; LeaveCriticalSection(&m_csXEnroll); return S_OK; } HRESULT CCEnroll::GetKeyArchivePKCS7( OUT CRYPT_ATTR_BLOB *pBlobKeyArchivePKCS7) { HRESULT hr; HCRYPTPROV hProv; HCRYPTKEY hKey = NULL; BYTE *pBlobPrivateKey = NULL; DWORD cBlobPrivateKey = 0; CRYPT_ENCRYPT_MESSAGE_PARA cemp; ALG_ID algId[] = {CALG_3DES, CALG_RC4, CALG_RC2, ALG_TYPE_ANY}; CRYPT_OID_INFO const *pOidInfo = NULL; DWORD i = 0; //init pBlobKeyArchivePKCS7->pbData = NULL; pBlobKeyArchivePKCS7->cbData = 0; EnterCriticalSection(&m_csXEnroll); //make sure key archival cert is set assert(NULL != m_PrivateKeyArchiveCertificate); PCCERT_CONTEXT apCert[] = {m_PrivateKeyArchiveCertificate}; //get user private key hProv = GetProv(0); //existing key container handle if (NULL == hProv) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptAcquireContextError; } if (NULL == m_hCachedKey) { //likely used existing key if(!CryptGetUserKey( hProv, m_keyProvInfo.dwKeySpec, &hKey)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptGetUserKeyError; } } //export private key while (TRUE) { if (!CryptExportKey( NULL != hKey ? hKey : m_hCachedKey, NULL, //don't encrypt PRIVATEKEYBLOB, 0, pBlobPrivateKey, &cBlobPrivateKey)) { //map to xenroll error hr = XENROLL_E_KEY_NOT_EXPORTABLE; goto CryptExportKeyError; } if (NULL != pBlobPrivateKey) { //done break; } pBlobPrivateKey = (BYTE*)MyCoTaskMemAlloc(cBlobPrivateKey); if (NULL == pBlobPrivateKey) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (NULL == m_hCachedKey) { //it could be csp not supporting CRYPT_ARCHIVABLE //got private key, now let's take care of key permission if (0x0 == (m_dwGenKeyFlags & CRYPT_EXPORTABLE)) { // user didn't ask exportable, turn it off DWORD dwFlags = 0; DWORD dwSize = sizeof(dwFlags); if (!CryptGetKeyParam( hKey, KP_PERMISSIONS, (BYTE*)&dwFlags, &dwSize, 0)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptGetKeyParamError; } #if DBG assert(dwSize = sizeof(dwFlags)); // make sure was on assert(0x0 != (dwFlags & CRYPT_EXPORT)); #endif //turn off exportable dwFlags = dwFlags & (~CRYPT_EXPORT); if (!CryptSetKeyParam( hKey, KP_PERMISSIONS, (BYTE*)&dwFlags, 0)) { //hr = MY_HRESULT_FROM_WIN32(GetLastError()); //goto CryptSetKeyParamError; hr = S_OK; //UNDONE, even ms csps have problem with this } } } //prepare for encryption ZeroMemory(&cemp, sizeof(cemp)); //avoid 0 assignment cemp.cbSize = sizeof(cemp); cemp.dwMsgEncodingType = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING; hr = S_OK; //critical init for double while loop while (ALG_TYPE_ANY != algId[i]) { pOidInfo = xeCryptFindOIDInfo( CRYPT_OID_INFO_ALGID_KEY, &algId[i], CRYPT_ENCRYPT_ALG_OID_GROUP_ID); if (NULL != pOidInfo) { cemp.ContentEncryptionAlgorithm.pszObjId = const_cast(pOidInfo->pszOID); //encryt into pkcs7 while (TRUE) { if (!CryptEncryptMessage( &cemp, sizeof(apCert)/sizeof(apCert[0]), apCert, pBlobPrivateKey, cBlobPrivateKey, pBlobKeyArchivePKCS7->pbData, &pBlobKeyArchivePKCS7->cbData)) { //save the 1st error code hr = MY_HRESULT_FROM_WIN32(GetLastError()); #ifdef DBG assert(NULL == pBlobKeyArchivePKCS7->pbData); #endif break; //break inner while loop } if (NULL != pBlobKeyArchivePKCS7->pbData) { //done, got encrypted blob //ignore error from previous alg tries hr = S_OK; break; } pBlobKeyArchivePKCS7->pbData = (BYTE*)MyCoTaskMemAlloc( pBlobKeyArchivePKCS7->cbData); if (NULL == pBlobKeyArchivePKCS7->pbData) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (S_OK == hr) { //done, out of outer while loop break; } } ++i; } if (NULL == pOidInfo) { hr = CRYPT_E_NOT_FOUND; goto CryptElemNotFoundError; } if (S_OK != hr) { goto CryptEncryptMessageError; } hr = S_OK; ErrorReturn: //now let's destroy cached key handle if (NULL != m_hCachedKey) { CryptDestroyKey(m_hCachedKey); m_hCachedKey = NULL; //critical to reset } //note, do above before leaving critical section LeaveCriticalSection(&m_csXEnroll); if (NULL != pBlobPrivateKey) { SecureZeroMemory(pBlobPrivateKey, cBlobPrivateKey); MyCoTaskMemFree(pBlobPrivateKey); } if (NULL != hKey) { CryptDestroyKey(hKey); } return hr; TRACE_ERROR(CryptEncryptMessageError) TRACE_ERROR(CryptAcquireContextError) TRACE_ERROR(CryptGetUserKeyError) TRACE_ERROR(CryptExportKeyError) TRACE_ERROR(OutOfMemoryError) TRACE_ERROR(CryptElemNotFoundError) //TRACE_ERROR(CryptSetKeyParamError) TRACE_ERROR(CryptGetKeyParamError) } HRESULT GetKeyProvInfoFromCert( IN PCCERT_CONTEXT pCert, OUT DWORD *pdwKeySpec, OUT HCRYPTPROV *phProv) { HRESULT hr; CRYPT_KEY_PROV_INFO *pKeyProvInfo = NULL; DWORD cb = 0; HCRYPTPROV hProv = NULL; if (NULL == pCert || NULL == phProv || NULL == pdwKeySpec) { hr = E_INVALIDARG; goto InvalidArgError; } while (TRUE) { if(!CertGetCertificateContextProperty( pCert, CERT_KEY_PROV_INFO_PROP_ID, pKeyProvInfo, &cb)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertGetCertificateContextPropertyError; } if (NULL != pKeyProvInfo) { //got it, done break; } pKeyProvInfo = (CRYPT_KEY_PROV_INFO*)LocalAlloc(LMEM_FIXED, cb); if (NULL == pKeyProvInfo) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } if (!CryptAcquireContextU( &hProv, pKeyProvInfo->pwszContainerName, pKeyProvInfo->pwszProvName, pKeyProvInfo->dwProvType, pKeyProvInfo->dwFlags)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptAcquireContextUError; } *phProv = hProv; hProv = NULL; *pdwKeySpec = pKeyProvInfo->dwKeySpec; hr = S_OK; ErrorReturn: if (NULL != pKeyProvInfo) { LocalFree(pKeyProvInfo); } if (NULL != hProv) { CryptReleaseContext(hProv, 0); } return hr; TRACE_ERROR(CryptAcquireContextUError) TRACE_ERROR(OutOfMemoryError) TRACE_ERROR(CertGetCertificateContextPropertyError) TRACE_ERROR(InvalidArgError) } HRESULT xeCreateKeyArchivalHashAttribute( IN CRYPT_HASH_BLOB *pBlobKAHash, OUT CRYPT_ATTR_BLOB *pBlobKAAttr) { HRESULT hr; BYTE *pbData = NULL; DWORD cbData = 0; while (TRUE) { if(!CryptEncodeObject( CRYPT_ASN_ENCODING, X509_OCTET_STRING, (void*)pBlobKAHash, pbData, &cbData)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CryptEncodeObjectError; } if (NULL != pbData) { //done break; } pbData = (BYTE*)LocalAlloc(LMEM_FIXED, cbData); if (NULL == pbData) { hr = E_OUTOFMEMORY; goto LocalAllocError; } } pBlobKAAttr->pbData = pbData; pBlobKAAttr->cbData = cbData; pbData = NULL; hr = S_OK; ErrorReturn: if (NULL != pbData) { LocalFree(pbData); } return hr; TRACE_ERROR(CryptEncodeObjectError) TRACE_ERROR(LocalAllocError) } HRESULT STDMETHODCALLTYPE CCEnroll::createRequestWStr( IN LONG Flags, IN LPCWSTR pwszDNName, IN LPCWSTR pwszUsage, OUT PCRYPT_DATA_BLOB pblobRequest) { HRESULT hr; CRYPT_DATA_BLOB blobPKCS10; CRYPT_ATTR_BLOB blobKeyArchivePKCS7; ALG_ID rgAlg[2]; PCCRYPT_OID_INFO pOidInfo; CERT_EXTENSION *rgExt = NULL; DWORD cExt = 0; CERT_EXTENSION *pExt = NULL; //for enum 1st CRYPT_ATTRIBUTE *rgAttr = NULL; DWORD cAttr = 0; CRYPT_ATTRIBUTE *pAttr = NULL; //for enum 1st CRYPT_ATTRIBUTES rgAttributes; CRYPT_ATTRIBUTE *rgUnauthAttr = NULL; //init DWORD cUnauthAttr = 0; //init DWORD cb; HCRYPTPROV hProvSigner = NULL; DWORD dwKeySpecSigner = 0; PCCERT_CONTEXT pCertSigner = NULL; //just init, no free HCRYPTPROV hRequestProv = NULL; BYTE *pbSubjectKeyHash = NULL; DWORD cbSubjectKeyHash = 0; CRYPT_HASH_BLOB blobKAHash; CRYPT_ATTR_BLOB blobKAHashAttr; CRYPT_ATTRIBUTE attrKAHash = {szOID_ENCRYPTED_KEY_HASH, 1, &blobKAHashAttr}; ZeroMemory(&blobPKCS10, sizeof(blobPKCS10)); ZeroMemory(&blobKeyArchivePKCS7, sizeof(blobKeyArchivePKCS7)); ZeroMemory(&blobKAHash, sizeof(blobKAHash)); ZeroMemory(&blobKAHashAttr, sizeof(blobKAHashAttr)); EnterCriticalSection(&m_csXEnroll); // BUG 533202: should block key archival when re-using key (from script) if (0 != m_dwEnabledSafteyOptions && NULL != m_PrivateKeyArchiveCertificate && m_fUseExistingKey) { hr = E_ACCESSDENIED; goto AccessDeniedError; } m_fNewRequestMethod = TRUE; //critical m_fOID_V2 = TRUE; m_fCMCFormat = FALSE; m_fHonorIncludeSubjectKeyID = FALSE; switch (Flags) { case XECR_CMC: { if (NULL != m_pCertContextRenewal && NULL != m_pCertContextSigner) { //don't support both on yet hr = MY_HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); goto NotSupportedError; } m_fCMCFormat = TRUE; m_fHonorIncludeSubjectKeyID = TRUE; // create pkcs 10 first hr = createPKCS10WStr( pwszDNName, pwszUsage, //wszPurpose, &blobPKCS10); if(S_OK != hr) { goto createPKCS10WStrError; } //set it back m_fCMCFormat = FALSE; //get all extensions cb = CountStackExtension(TRUE) * sizeof(CERT_EXTENSION); if (0 < cb) { rgExt = (CERT_EXTENSION*)LocalAlloc(LMEM_FIXED, cb); if (NULL == rgExt) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } ZeroMemory(rgExt, cb); while(NULL != (pExt = EnumStackExtension(pExt, TRUE))) { rgExt[cExt] = *pExt; cExt++; } } //get all attributes including namevalue pair cb = CountStackAttribute(TRUE) * sizeof(CRYPT_ATTRIBUTE); if (NULL != m_PrivateKeyArchiveCertificate) { //add one more attribute to hold encrypted key hash cb += sizeof(CRYPT_ATTRIBUTE); } if (0 < cb) { rgAttr = (CRYPT_ATTRIBUTE*)LocalAlloc(LMEM_FIXED, cb); if (NULL == rgAttr) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } ZeroMemory(rgAttr, cb); while(NULL != (pAttr = EnumStackAttribute(pAttr, TRUE))) { rgAttr[cAttr] = *pAttr; cAttr++; } rgAttributes.rgAttr = rgAttr; rgAttributes.cAttr = cAttr; } if (NULL != m_PrivateKeyArchiveCertificate) { hr = GetKeyArchivePKCS7(&blobKeyArchivePKCS7); if (S_OK != hr) { goto GetKeyArchivePKCS7Error; } rgUnauthAttr = (CRYPT_ATTRIBUTE*)LocalAlloc(LMEM_FIXED, sizeof(CRYPT_ATTRIBUTE)); if (NULL == rgUnauthAttr) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } rgUnauthAttr->pszObjId = szOID_ARCHIVED_KEY_ATTR; rgUnauthAttr->cValue = 1; rgUnauthAttr->rgValue = &blobKeyArchivePKCS7; ++cUnauthAttr; //if key archival cert is set, should save the hash //of the encrypted private key hr = myCalculateKeyArchivalHash( blobKeyArchivePKCS7.pbData, blobKeyArchivePKCS7.cbData, &blobKAHash.pbData, &blobKAHash.cbData); if (S_OK != hr) { goto myCalculateKeyArchivalHashError; } if (!CertSetCertificateContextProperty( m_pCertContextPendingRequest, //use pending cert CERT_ARCHIVED_KEY_HASH_PROP_ID, 0, &blobKAHash)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertSetCertificateContextPropertyError; } hr = xeCreateKeyArchivalHashAttribute( &blobKAHash, &blobKAHashAttr); if (S_OK != hr) { goto xeCreateKeyArchivalHashAttributeError; } //add this attribute into the array rgAttr[cAttr] = attrKAHash; cAttr++; rgAttributes.rgAttr = rgAttr; rgAttributes.cAttr = cAttr; } //client may set m_HashAlgId but it is not guaranteed //GetCapiHashAndSigAlgId will determine which one //is actually used if (!GetCapiHashAndSigAlgId(rgAlg)) { hr = NTE_BAD_ALGID; goto GetCapiHashAndSigAlgIdError; } pOidInfo = xeCryptFindOIDInfo( CRYPT_OID_INFO_ALGID_KEY, (void*)rgAlg, //point to rgAlg[0] CRYPT_HASH_ALG_OID_GROUP_ID); if (NULL == pOidInfo) { goto xeCryptFindOIDInfoError; } if (NULL != m_pCertContextRenewal) { pCertSigner = m_pCertContextRenewal; } if (NULL != m_pCertContextSigner) { pCertSigner = m_pCertContextSigner; } if (NULL != pCertSigner) { //get signer key prov info hr = GetKeyProvInfoFromCert( pCertSigner, &dwKeySpecSigner, &hProvSigner); if (S_OK != hr) { goto GetKeyProvInfoFromCertError; } } //this is CMC, honor anyway if (m_fIncludeSubjectKeyID) { hr = myGetPublicKeyHash( NULL, m_pPublicKeyInfo, &pbSubjectKeyHash, &cbSubjectKeyHash); if (S_OK != hr) { goto myGetPublicKeyHashError; } } hRequestProv = GetProv(0); if (NULL == hRequestProv) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto GetProvError; } //ok, now call cmc create hr = BuildCMCRequest( m_lClientId, FALSE, //fNestedCMCRequest blobPKCS10.pbData, blobPKCS10.cbData, rgExt, cExt, (0 != cAttr) ? &rgAttributes : NULL, (0 != cAttr) ? 1 : 0, rgUnauthAttr, cUnauthAttr, pbSubjectKeyHash, cbSubjectKeyHash, hRequestProv, m_keyProvInfo.dwKeySpec, pOidInfo->pszOID, pCertSigner, hProvSigner, dwKeySpecSigner, NULL, //pOidInfo->pszOID, //this seems to me not necessary because we passed the cert context &pblobRequest->pbData, &pblobRequest->cbData); if (S_OK != hr) { goto BuildCMCRequestError; } } break; case XECR_PKCS7: if ((NULL == m_pCertContextRenewal && NULL == m_pCertContextSigner) || NULL != m_PrivateKeyArchiveCertificate) { //renew cert is not set, can't make it pkcs7 //pkcs7 can't support key archival hr = E_INVALIDARG; goto InvalidArgError; } // old method will return pkcs7 hr = createPKCS10WStr( pwszDNName, pwszUsage, //wszPurpose, pblobRequest); if(S_OK != hr) { goto createPKCS10WStrError; } break; case XECR_PKCS10_V1_5: m_fOID_V2 = FALSE; //fall through case XECR_PKCS10_V2_0: if (NULL != m_PrivateKeyArchiveCertificate) { //pkcs10 can't support key archival hr = E_INVALIDARG; goto InvalidArgError; } m_fHonorRenew = FALSE; //avoid return pkcs7 //for new PKCS10 we allow include subject key id extension m_fHonorIncludeSubjectKeyID = TRUE; // call old method hr = createPKCS10WStr( pwszDNName, pwszUsage, //wszPurpose, pblobRequest); if(S_OK != hr) { goto createPKCS10WStrError; } break; default: hr = E_INVALIDARG; goto InvalidArgError; break; } //in all cases, we called createPKCS10WStr if(m_wszPVKFileName[0] != 0 && !m_fUseExistingKey) { //we hold on this until possible cmc is created GetProv(CRYPT_DELETEKEYSET); } hr = S_OK; ErrorReturn: m_fNewRequestMethod = FALSE; //critical m_fOID_V2 = FALSE; //critical for backward compatiability m_fHonorRenew = TRUE; //critical m_fHonorIncludeSubjectKeyID = TRUE; //critical for backward compt. LeaveCriticalSection(&m_csXEnroll); if (NULL != rgExt) { LocalFree(rgExt); } if (NULL != rgAttr) { LocalFree(rgAttr); } if (NULL != rgUnauthAttr) { LocalFree(rgUnauthAttr); } if (NULL != blobKeyArchivePKCS7.pbData) { MyCoTaskMemFree(blobKeyArchivePKCS7.pbData); } if (NULL != blobPKCS10.pbData) { MyCoTaskMemFree(blobPKCS10.pbData); } if (NULL != hProvSigner) { CryptReleaseContext(hProvSigner, 0); } if (NULL != pbSubjectKeyHash) { LocalFree(pbSubjectKeyHash); } if (NULL != blobKAHash.pbData) { LocalFree(blobKAHash.pbData); } if (NULL != blobKAHashAttr.pbData) { LocalFree(blobKAHashAttr.pbData); } return hr; TRACE_ERROR(AccessDeniedError); TRACE_ERROR(createPKCS10WStrError) TRACE_ERROR(BuildCMCRequestError) TRACE_ERROR(InvalidArgError) TRACE_ERROR(GetCapiHashAndSigAlgIdError) TRACE_ERROR(GetKeyArchivePKCS7Error) TRACE_ERROR(xeCryptFindOIDInfoError) TRACE_ERROR(OutOfMemoryError) TRACE_ERROR(GetKeyProvInfoFromCertError) TRACE_ERROR(NotSupportedError) TRACE_ERROR(GetProvError) TRACE_ERROR(myGetPublicKeyHashError) TRACE_ERROR(CertSetCertificateContextPropertyError) TRACE_ERROR(myCalculateKeyArchivalHashError) TRACE_ERROR(xeCreateKeyArchivalHashAttributeError) } HRESULT CCEnroll::BlobToBstring( IN CRYPT_DATA_BLOB *pBlob, IN DWORD dwFlag, OUT BSTR *pBString) { HRESULT hr; WCHAR *pwszB64; DWORD cch; //init *pBString = NULL; // BASE64 encode blob pwszB64 = NULL; cch = 0; while (TRUE) { if (!MyCryptBinaryToStringW( pBlob->pbData, pBlob->cbData, dwFlag, pwszB64, &cch)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptBinaryToStringWError; } if (NULL != pwszB64) { //got it, done break; } pwszB64 = (WCHAR *)LocalAlloc(LMEM_FIXED, cch * sizeof(WCHAR)); if (NULL == pwszB64) { hr = E_OUTOFMEMORY; goto OutOfMemoryError; } } // SysAllocStringLen *pBString = SysAllocStringLen(pwszB64, cch); if(NULL == *pBString) { SetLastError(ERROR_OUTOFMEMORY); hr = E_OUTOFMEMORY; goto SysAllocStringLenError; } hr = S_OK; ErrorReturn: if (NULL != pwszB64) { LocalFree(pwszB64); } return(hr); TRACE_ERROR(MyCryptBinaryToStringWError) TRACE_ERROR(SysAllocStringLenError) TRACE_ERROR(OutOfMemoryError) } HRESULT CCEnroll::BstringToBlob( IN BSTR bString, OUT CRYPT_DATA_BLOB *pBlob) { HRESULT hr; assert(NULL != pBlob); //init pBlob->pbData = NULL; pBlob->cbData = 0; while (TRUE) { if (!MyCryptStringToBinaryW( (LPCWSTR)bString, SysStringLen(bString), CRYPT_STRING_ANY, pBlob->pbData, &pBlob->cbData, NULL, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto MyCryptStringToBinaryWError; } if (NULL != pBlob->pbData) { break; //done } pBlob->pbData = (BYTE*)MyCoTaskMemAlloc(pBlob->cbData); if (NULL == pBlob->pbData) { hr = E_OUTOFMEMORY; goto MyCoTaskMemAllocError; } } hr = S_OK; ErrorReturn: return(hr); TRACE_ERROR(MyCoTaskMemAllocError) TRACE_ERROR(MyCryptStringToBinaryWError) } HRESULT CCEnroll::createRequestWStrBStr( IN LONG Flags, IN LPCWSTR pwszDNName, IN LPCWSTR pwszUsage, IN DWORD dwFlag, OUT BSTR __RPC_FAR *pbstrRequest) { HRESULT hr; CRYPT_DATA_BLOB blobRequest; memset(&blobRequest, 0, sizeof(blobRequest)); hr = createRequestWStr(Flags, pwszDNName, pwszUsage, &blobRequest); if (S_OK != hr) { goto createRequestWStrError; } // convert to bstr hr = BlobToBstring(&blobRequest, dwFlag, pbstrRequest); if (S_OK != hr) { goto BlobToBstringError; } hr = S_OK; ErrorReturn: if(NULL != blobRequest.pbData) { MyCoTaskMemFree(blobRequest.pbData); } return(hr); TRACE_ERROR(createRequestWStrError) TRACE_ERROR(BlobToBstringError) } HRESULT CCEnroll::BStringToFile( IN BSTR bString, IN LPCWSTR pwszFileName) { HRESULT hr; HANDLE hFile = NULL; DWORD cb = 0; LPSTR sz = NULL; size_t nLength; sz = MBFromWide(bString); if(NULL == sz) { hr = E_OUTOFMEMORY; goto MBFromWideError; } nLength = strlen(sz); if (nLength > (DWORD)-1) goto InvalidArgError; // open the file hFile = CreateFileSafely(pwszFileName); if (NULL == hFile) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CreateFileFileSafelyError; } // write the pkcs10 if(!WriteFile( hFile, sz, (DWORD)nLength, &cb, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto WriteFileError; } hr = S_OK; ErrorReturn: if(NULL != hFile) { CloseHandle(hFile); } if(NULL != sz) { MyCoTaskMemFree(sz); } return(hr); TRACE_ERROR(CreateFileFileSafelyError) SET_HRESULT(InvalidArgError, E_INVALIDARG); TRACE_ERROR(MBFromWideError) TRACE_ERROR(WriteFileError) } HRESULT STDMETHODCALLTYPE CCEnroll::createFileRequestWStr( IN LONG Flags, IN LPCWSTR pwszDNName, IN LPCWSTR pwszUsage, IN LPCWSTR pwszRequestFileName) { HRESULT hr; BSTR bstrRequest = NULL; // get the Request hr = createRequestWStrBStr( Flags, pwszDNName, pwszUsage, CRYPT_STRING_BASE64REQUESTHEADER, &bstrRequest); if(S_OK != hr) { goto createRequestWStrBStrError; } // save it to file hr = BStringToFile(bstrRequest, pwszRequestFileName); if (S_OK != hr) { goto BStringToFileError; } hr = S_OK; ErrorReturn: if(NULL != bstrRequest) { SysFreeString(bstrRequest); } return(hr); TRACE_ERROR(createRequestWStrBStrError) TRACE_ERROR(BStringToFileError) } HRESULT STDMETHODCALLTYPE CCEnroll::acceptResponseBlob( IN PCRYPT_DATA_BLOB pblobResponse) { HRESULT hr_old = S_OK; HRESULT hr; XCMCRESPONSE *prgResponse = NULL; DWORD cResponse = 0; EnterCriticalSection(&m_csXEnroll); //check in parameter if (NULL == pblobResponse) { hr = E_POINTER; goto NullPointerError; } if (NULL == pblobResponse->pbData || 0 == pblobResponse->cbData) { hr = E_INVALIDARG; goto InvalidArgError; } //make sure init archived key hash ZeroMemory(&m_blobResponseKAHash, sizeof(m_blobResponseKAHash)); hr_old = ParseCMCResponse( pblobResponse->pbData, pblobResponse->cbData, NULL, &prgResponse, &cResponse); //note, if for any reasons above failed, try pkcs7 if (S_OK == hr_old) { if (1 < cResponse) { //not supported yet hr = MY_HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); goto NotSupportedError; } #if DBG //make sure not zero, should be 1 assert(1 == cResponse); #endif //DBG //check response status if (CMC_STATUS_SUCCESS != prgResponse->StatusInfo.dwStatus) { hr = prgResponse->StatusInfo.dwStatus; //take status error goto CMCResponseStatusError; } //some code here to get encrypted archived key hash from the response //and make m_blobResponseKAHash point to the hash data if (NULL != prgResponse->pbEncryptedKeyHash) { m_blobResponseKAHash.pbData = prgResponse->pbEncryptedKeyHash; m_blobResponseKAHash.cbData = prgResponse->cbEncryptedKeyHash; } } //note, hr_old may not be S_OK, accept the response as pkcs7 hr = acceptPKCS7Blob(pblobResponse); if (S_OK != hr) { if (S_OK != hr_old) { //return old error instead of new one hr = hr_old; } goto acceptPKCS7BlobError; } hr = S_OK; ErrorReturn: //reset hash to zero ZeroMemory(&m_blobResponseKAHash, sizeof(m_blobResponseKAHash)); LeaveCriticalSection(&m_csXEnroll); if (NULL != prgResponse) { FreeCMCResponse(prgResponse, cResponse); } return hr; TRACE_ERROR(acceptPKCS7BlobError) TRACE_ERROR(CMCResponseStatusError) TRACE_ERROR(NotSupportedError) TRACE_ERROR(InvalidArgError) TRACE_ERROR(NullPointerError) } HRESULT STDMETHODCALLTYPE CCEnroll::acceptFileResponseWStr( IN LPCWSTR pwszResponseFileName) { HRESULT hr; CRYPT_DATA_BLOB blob; ZeroMemory(&blob, sizeof(blob)); hr = xeStringToBinaryFromFile( pwszResponseFileName, &blob.pbData, &blob.cbData, CRYPT_STRING_ANY); if (S_OK != hr) { goto xeStringToBinaryFromFileError; } // accept the blob hr = acceptResponseBlob(&blob); ErrorReturn: if (NULL != blob.pbData) { LocalFree(blob.pbData); } return(hr); TRACE_ERROR(xeStringToBinaryFromFileError) } HRESULT STDMETHODCALLTYPE CCEnroll::getCertContextFromResponseBlob( IN PCRYPT_DATA_BLOB pblobResponse, OUT PCCERT_CONTEXT *ppCertContext) { HRESULT hr; if (NULL == ppCertContext) { hr = E_POINTER; goto NullPointerError; } //???should check response status? //response is already in pkcs7 hr = GetEndEntityCert(pblobResponse, FALSE, ppCertContext); if (S_OK != hr) { goto GetEndEntityCertError; } hr = S_OK; ErrorReturn: return hr; TRACE_ERROR(NullPointerError) TRACE_ERROR(GetEndEntityCertError) } HRESULT STDMETHODCALLTYPE CCEnroll::getCertContextFromFileResponseWStr( IN LPCWSTR pwszResponseFileName, OUT PCCERT_CONTEXT *ppCertContext) { HRESULT hr; CRYPT_DATA_BLOB blobResponse; ZeroMemory(&blobResponse, sizeof(blobResponse)); // could be any form, binary or base64 hr = xeStringToBinaryFromFile( pwszResponseFileName, &blobResponse.pbData, &blobResponse.cbData, CRYPT_STRING_ANY); if (S_OK != hr) { goto xeStringToBinaryFromFileError; } hr = getCertContextFromResponseBlob( &blobResponse, ppCertContext); if (S_OK != hr) { goto getCertContextFromResponseBlobError; } hr = S_OK; ErrorReturn: if (NULL != blobResponse.pbData) { LocalFree(blobResponse.pbData); } return hr; TRACE_ERROR(xeStringToBinaryFromFileError) TRACE_ERROR(getCertContextFromResponseBlobError) } HRESULT STDMETHODCALLTYPE CCEnroll::createPFXWStr( IN LPCWSTR pwszPassword, OUT PCRYPT_DATA_BLOB pblobPFX) { HRESULT hr; HCERTSTORE hMemStore = NULL; DWORD i; CERT_CHAIN_CONTEXT const *pCertChainContext = NULL; CERT_CHAIN_PARA CertChainPara; CERT_SIMPLE_CHAIN *pSimpleChain; EnterCriticalSection(&m_csXEnroll); if (NULL == pblobPFX) { goto EPointerError; } if (NULL == m_pCertContextStatic) { hr = E_UNEXPECTED; goto UnexpectedError; } // create a memory store for cert and chain hMemStore = CertOpenStore( CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, NULL, 0, NULL); if (NULL == hMemStore) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertOpenStoreError; } ZeroMemory(&CertChainPara, sizeof(CertChainPara)); CertChainPara.cbSize = sizeof(CertChainPara); // try to build cert and chain if (!MyCertGetCertificateChain( HCCE_CURRENT_USER, m_pCertContextStatic, NULL, NULL, &CertChainPara, 0, NULL, &pCertChainContext)) { //use 1st hr error hr = MY_HRESULT_FROM_WIN32(GetLastError()); //try local machine if (!MyCertGetCertificateChain( HCCE_LOCAL_MACHINE, m_pCertContextStatic, NULL, NULL, &CertChainPara, 0, NULL, &pCertChainContext)) { //still use 1st hr goto MyCertGetCertificateChainError; } } // make sure there is at least 1 simple chain if (0 == pCertChainContext->cChain) { hr = MY_HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); goto NoCertificateChainError; } //add chain to memory store pSimpleChain = pCertChainContext->rgpChain[0]; for (i = 0; i < pSimpleChain->cElement; i++) { if (!CertAddCertificateContextToStore( hMemStore, pSimpleChain->rgpElement[i]->pCertContext, CERT_STORE_ADD_REPLACE_EXISTING, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CertAddCertificateContextToStoreError; } } pblobPFX->pbData = NULL; while (TRUE) { if (!PFXExportCertStore( hMemStore, pblobPFX, pwszPassword, EXPORT_PRIVATE_KEYS | REPORT_NOT_ABLE_TO_EXPORT_PRIVATE_KEY)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto PFXExportCertStoreError; } if (NULL != pblobPFX->pbData) { //got it, done break; } pblobPFX->pbData = (BYTE*)MyCoTaskMemAlloc(pblobPFX->cbData); if (NULL == pblobPFX->pbData) { hr = E_OUTOFMEMORY; goto MyCoTaskMemAllocError; } } hr = S_OK; ErrorReturn: LeaveCriticalSection(&m_csXEnroll); if (pCertChainContext != NULL) { MyCertFreeCertificateChain(pCertChainContext); } if (NULL != hMemStore) { CertCloseStore(hMemStore, CERT_CLOSE_STORE_CHECK_FLAG); } return hr; TRACE_ERROR(UnexpectedError) TRACE_ERROR(CertOpenStoreError) TRACE_ERROR(PFXExportCertStoreError) TRACE_ERROR(MyCoTaskMemAllocError) TRACE_ERROR(CertAddCertificateContextToStoreError) TRACE_ERROR(NoCertificateChainError) TRACE_ERROR(MyCertGetCertificateChainError) SET_HRESULT(EPointerError, E_POINTER) } HRESULT CCEnroll::createPFXWStrBStr( IN LPCWSTR pwszPassword, OUT BSTR __RPC_FAR *pbstrPFX) { HRESULT hr; CRYPT_DATA_BLOB blobPFX; memset(&blobPFX, 0, sizeof(CRYPT_DATA_BLOB)); hr = createPFXWStr(pwszPassword, &blobPFX); if (S_OK != hr) { goto createPFXWStrError; } // convert pfx to bstr hr = BlobToBstring(&blobPFX, CRYPT_STRING_BASE64, pbstrPFX); if (S_OK != hr) { goto BlobToBstringError; } hr = S_OK; ErrorReturn: if(NULL != blobPFX.pbData) { MyCoTaskMemFree(blobPFX.pbData); } return(hr); TRACE_ERROR(createPFXWStrError) TRACE_ERROR(BlobToBstringError) } HRESULT STDMETHODCALLTYPE CCEnroll::createFilePFXWStr( IN LPCWSTR pwszPassword, IN LPCWSTR pwszPFXFileName) { HRESULT hr; HANDLE hFile = NULL; DWORD cb = 0; CRYPT_DATA_BLOB blobPFX; memset(&blobPFX, 0, sizeof(CRYPT_DATA_BLOB)); hr = createPFXWStr(pwszPassword, &blobPFX); if (S_OK != hr) { goto createPFXWStrError; } // open the file hFile = CreateFileSafely(pwszPFXFileName); if (NULL == hFile) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto CreateFileFileSafelyError; } // write the pkcs10 if(!WriteFile( hFile, blobPFX.pbData, blobPFX.cbData, &cb, NULL)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); goto WriteFileError; } hr = S_OK; ErrorReturn: if(NULL != hFile) { CloseHandle(hFile); } if(NULL != blobPFX.pbData) { MyCoTaskMemFree(blobPFX.pbData); } return(hr); TRACE_ERROR(createPFXWStrError) TRACE_ERROR(CreateFileFileSafelyError) TRACE_ERROR(WriteFileError) } HRESULT STDMETHODCALLTYPE CCEnroll::setPendingRequestInfoWStr( IN LONG lRequestID, IN LPCWSTR pwszCADNS, IN LPCWSTR pwszCAName, IN LPCWSTR pwszFriendlyName ) { //------------------------------------------------------------ // // Define locally-scoped helper functions: // //------------------------------------------------------------ CEnrollLocalScope(SetPendingRequestInfoHelper): // Finds the appropriate cert context to set pending info on using the following algorithm: // 1) If a hash value HAS NOT been specified, use the cached cert request. // 2) If a hash value HAS been specified, search the request store for a cert with an equivalent // hash value and return it. If no such cert can be found, return an error code. HRESULT GetPendingRequestCertContext(IN HCERTSTORE hStoreRequest, IN CRYPT_DATA_BLOB hashBlob, IN PCCERT_CONTEXT pCertContextCachedPendingRequest, OUT PCCERT_CONTEXT *pCertContextPendingRequest) { EquivalentHashCertContextFilter filter(hashBlob); if (hashBlob.pbData == NULL) { // We haven't specified a particular context, use the one we've cached. *pCertContextPendingRequest = CertDuplicateCertificateContext(pCertContextCachedPendingRequest); return S_OK; } else { // Returns the first certificate in the request store with a hash matching // pHashBlob. return FilteredCertEnumCertificatesInStore (hStoreRequest, NULL, &filter, pCertContextPendingRequest); } } DWORD GetPendingInfoBlobSize(IN LONG lRequestID, IN LPCWSTR pwszCADNS, IN LPCWSTR pwszCAName, IN LPCWSTR pwszFriendlyName) { assert(pwszCADNS != NULL && pwszCAName != NULL && pwszFriendlyName != NULL); return (DWORD)(sizeof(lRequestID) + // Request ID sizeof(DWORD) + // wcslen(pwszCADNS) sizeof(WCHAR) * (wcslen(pwszCADNS) + 1) + // pwszCADNS sizeof(DWORD) + // wcslen(pwszCAName) sizeof(WCHAR) * (wcslen(pwszCAName) + 1) + // pwszCAName sizeof(DWORD) + // wcslen(pwszFriendlyName) sizeof(WCHAR) * (wcslen(pwszFriendlyName) + 1) // pwszFriendlyName ); } // Combines the supplied pending request information into a CRYPT_DATA_BLOB // See wincrypt.h for the format. void MakePendingInfoBlob(IN LONG lRequestID, IN LPCWSTR pwszCADNS, IN LPCWSTR pwszCAName, IN LPCWSTR pwszFriendlyName, OUT CRYPT_DATA_BLOB pendingInfoBlob) { LPBYTE pbBlob; // None of the inputs should be NULL. assert(pwszCADNS != NULL && pwszCAName != NULL && pwszFriendlyName != NULL); // Declare an array of the strings we wish to write to the pending info blob struct StringsToWrite { DWORD cc; LPCWSTR pwsz; } rgStrings[] = { { (DWORD)wcslen(pwszCADNS) + 1, pwszCADNS }, { (DWORD)wcslen(pwszCAName) + 1, pwszCAName }, { (DWORD)wcslen(pwszFriendlyName) + 1, pwszFriendlyName } }; // Write the request ID to the blob pbBlob = pendingInfoBlob.pbData; memcpy(pbBlob, &lRequestID, sizeof(lRequestID)); pbBlob += sizeof(lRequestID); // Write all strings to the blob for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgStrings); dwIndex++) { memcpy(pbBlob, &rgStrings[dwIndex].cc, sizeof(rgStrings[dwIndex].cc)); pbBlob += sizeof(rgStrings[dwIndex].cc); memcpy(pbBlob, rgStrings[dwIndex].pwsz, rgStrings[dwIndex].cc * sizeof(WCHAR)); pbBlob += rgStrings[dwIndex].cc * sizeof(WCHAR); } assert(pbBlob == (pendingInfoBlob.pbData + pendingInfoBlob.cbData)); } CEnrollEndLocalScope; //------------------------------------------------------------ // // Begin procedure body. // //------------------------------------------------------------ CRYPT_DATA_BLOB pendingInfoBlob; HCERTSTORE hStoreRequest; HRESULT hr = S_OK; PCCERT_CONTEXT pCertContextPendingRequest = NULL; ZeroMemory(&pendingInfoBlob, sizeof(pendingInfoBlob)); EnterCriticalSection(&m_csXEnroll); // Input validation: if (lRequestID < 0 || pwszCADNS == NULL || pwszCAName == NULL) goto InvalidArgErr; // NULL is a valid value for pwszFriendlyName. If friendly name is NULL, replace with the empty string: if (pwszFriendlyName == NULL) { pwszFriendlyName = L""; } if (NULL == (hStoreRequest = GetStore(StoreREQUEST)) ) goto GetStoreErr; // Use our locally-scoped helper function to acquire the appropriate certificate context. if (S_OK != (hr = local.GetPendingRequestCertContext (hStoreRequest, m_hashBlobPendingRequest, m_pCertContextPendingRequest, &pCertContextPendingRequest))) goto GetPendingRequestCertContextErr; // Allocate memory for our pending info blob: pendingInfoBlob.cbData = local.GetPendingInfoBlobSize (lRequestID, pwszCADNS, pwszCAName, pwszFriendlyName); pendingInfoBlob.pbData = (LPBYTE)LocalAlloc(LPTR, pendingInfoBlob.cbData); if (NULL == pendingInfoBlob.pbData) goto MemoryErr; // Combine our arguments into a "pending info" blob. local.MakePendingInfoBlob (lRequestID, pwszCADNS, pwszCAName, pwszFriendlyName, pendingInfoBlob); // Use our pending info blob to assign the certificate context property. if (!CertSetCertificateContextProperty (pCertContextPendingRequest, CERT_ENROLLMENT_PROP_ID, 0, &pendingInfoBlob)) { // Failed to set the context property. goto CertSetCertificateContextPropertyErr; } // We've completed successfully. hr = S_OK; CommonReturn: if (NULL != pendingInfoBlob.pbData) { LocalFree(pendingInfoBlob.pbData); } if (NULL != pCertContextPendingRequest) { CertFreeCertificateContext(pCertContextPendingRequest); } LeaveCriticalSection(&m_csXEnroll); return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(CertSetCertificateContextPropertyErr, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(GetPendingRequestCertContextErr, hr); SET_HRESULT(GetStoreErr, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(InvalidArgErr, E_INVALIDARG); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); } //-------------------------------------------------------------------------------- // // THIS METHOD IS NOT SAFE FOR SCRIPTING // //-------------------------------------------------------------------------------- HRESULT STDMETHODCALLTYPE CCEnroll::enumPendingRequestWStr( IN LONG lIndex, IN LONG lDesiredProperty, OUT LPVOID ppProperty ) { //------------------------------------------------------------ // // Define locally scoped helper functions. // //------------------------------------------------------------ CEnrollLocalScope(EnumPendingRequestHelper): CRYPT_DATA_BLOB dataBlob; HRESULT GetContextPropertySimple(PCCERT_CONTEXT pCertContext, DWORD dwPropID) { BOOL fDone = FALSE; dataBlob.pbData = NULL; dataBlob.cbData = 0x150; do { if (dataBlob.pbData != NULL) { LocalFree(dataBlob.pbData); } dataBlob.pbData = (LPBYTE)LocalAlloc(LPTR, dataBlob.cbData); if (dataBlob.pbData == NULL) { return E_OUTOFMEMORY; } if (!CertGetCertificateContextProperty (pCertContext, dwPropID, (LPVOID)dataBlob.pbData, &(dataBlob.cbData))) { if (GetLastError() != ERROR_MORE_DATA) return MY_HRESULT_FROM_WIN32(GetLastError()); } else { fDone = TRUE; } } while (!fDone); return S_OK; } // Extracts the next packed string from our pending info blob. // If pbString is non-NULL, it must be large enough to hold the entire string. LPBYTE GetNextString(IN LPBYTE pbBlob, OUT DWORD *pcbSize, OUT LPBYTE pbString) { DWORD dwSize; memcpy(&dwSize, pbBlob, sizeof(DWORD)); dwSize *= sizeof(WCHAR); // Convert to count in bytes. if (NULL != pcbSize) { *pcbSize = dwSize; } pbBlob += sizeof(DWORD); if (NULL != pbString) { memcpy(pbString, pbBlob, dwSize); } pbBlob += dwSize; return pbBlob; } HRESULT getRequestID(PCCERT_CONTEXT pCertContext, long *pplProperty) { HRESULT hr; if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID))) *pplProperty = *((long *)dataBlob.pbData); return hr; } HRESULT getCAName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) { DWORD dwSize; HRESULT hr; LPBYTE pb; if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID))) { pb = dataBlob.pbData + sizeof(DWORD); // pb points to DNS Name blob pb = GetNextString(pb, NULL, NULL); // pb points to CA Name blob GetNextString(pb, &dwSize, NULL); // dwSize = size in chars of CA Name // If pbData is NULL, we're just doing a size check. if (pDataBlobProperty->pbData != NULL) { if (pDataBlobProperty->cbData < dwSize) { hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA); } else { GetNextString(pb, NULL, pDataBlobProperty->pbData); } } pDataBlobProperty->cbData = dwSize; } return hr; } HRESULT getCADNSName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) { DWORD dwSize; HRESULT hr; LPBYTE pb; if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID))) { pb = dataBlob.pbData + sizeof(DWORD); // pb points to DNS Name blob GetNextString(pb, &dwSize, NULL); // dwSize = size in chars of CA Name // If pbData is NULL, we're just doing a size check. if (pDataBlobProperty->pbData != NULL) { if (pDataBlobProperty->cbData < dwSize) { hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA); } else { GetNextString(pb, NULL, pDataBlobProperty->pbData); } } pDataBlobProperty->cbData = dwSize; } return hr; } HRESULT getCAFriendlyName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) { DWORD dwSize; HRESULT hr; LPBYTE pb; if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_ENROLLMENT_PROP_ID))) { // Set pb to point to the start of the CA name blob pb = dataBlob.pbData + sizeof(DWORD); // pb points to DNS Name blob pb = GetNextString(pb, NULL, NULL); // pb points to CA Name blob pb = GetNextString(pb, NULL, NULL); // pb points to Friendly Name blob // dwSize <-- size in chars of CA Name GetNextString(pb, &dwSize, NULL); // If pbData is NULL, we're just doing a size check. if (pDataBlobProperty->pbData != NULL) { if (pDataBlobProperty->cbData < dwSize) { hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA); } else { GetNextString(pb, NULL, pDataBlobProperty->pbData); } } pDataBlobProperty->cbData = dwSize; } return hr; } HRESULT getHash(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) { HRESULT hr; if (S_OK == (hr = GetContextPropertySimple(pCertContext, CERT_HASH_PROP_ID))) { // If pbData is NULL, we're just doing a size check. if (pDataBlobProperty->pbData != NULL) { if (pDataBlobProperty->cbData < dataBlob.cbData) { hr = MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA); } else { memcpy(pDataBlobProperty->pbData, dataBlob.pbData, dataBlob.cbData); } } pDataBlobProperty->cbData = dataBlob.cbData; } return hr; } HRESULT getDate(PCCERT_CONTEXT pCertContext, PFILETIME pftProperty) { *pftProperty = pCertContext->pCertInfo->NotAfter; return S_OK; } HRESULT getTemplateName(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) { CERT_NAME_VALUE *pCertTemplateNameValue = NULL; DWORD cbCertTemplateNameValue; DWORD cbRequired = 0; HRESULT hr = S_OK; PCERT_EXTENSION pCertTemplateExtension = NULL; if (NULL == (pCertTemplateExtension = CertFindExtension (szOID_ENROLL_CERTTYPE_EXTENSION, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension))) return E_INVALIDARG; if (!CryptDecodeObject (pCertContext->dwCertEncodingType, X509_UNICODE_ANY_STRING, pCertTemplateExtension->Value.pbData, pCertTemplateExtension->Value.cbData, 0, NULL, &cbCertTemplateNameValue) || (cbCertTemplateNameValue == 0)) goto CryptDecodeObjectErr; pCertTemplateNameValue = (CERT_NAME_VALUE *)LocalAlloc(LPTR, cbCertTemplateNameValue); if (NULL == pCertTemplateNameValue) goto MemoryErr; if (!CryptDecodeObject (pCertContext->dwCertEncodingType, X509_UNICODE_ANY_STRING, pCertTemplateExtension->Value.pbData, pCertTemplateExtension->Value.cbData, 0, (void *)(pCertTemplateNameValue), &cbCertTemplateNameValue)) goto CryptDecodeObjectErr; cbRequired = sizeof(WCHAR) * (DWORD)(wcslen((LPWSTR)(pCertTemplateNameValue->Value.pbData)) + 1); if (NULL != pDataBlobProperty->pbData) { // Make sure we've allocated a large enough buffer: if (pDataBlobProperty->cbData < cbRequired) { goto MoreDataErr; } // Write the template name to the OUT param: wcscpy((LPWSTR)pDataBlobProperty->pbData, (LPWSTR)(pCertTemplateNameValue->Value.pbData)); } hr = S_OK; CommonReturn: // Assign the size of the template name to the cb of the OUT param. // This should be done for all code paths. pDataBlobProperty->cbData = cbRequired; // Free resources: if (NULL != pCertTemplateNameValue) { LocalFree(pCertTemplateNameValue); } return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(CryptDecodeObjectErr, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(MoreDataErr, MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA)); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); } HRESULT getTemplateOID(PCCERT_CONTEXT pCertContext, PCRYPT_DATA_BLOB pDataBlobProperty) { CERT_TEMPLATE_EXT *pCertTemplateExt = NULL; DWORD cbCertTemplateExt = 0; DWORD cbRequired = 0; HRESULT hr; LPWSTR pwszOID = NULL; PCERT_EXTENSION pCertExtension = NULL; if (NULL == (pCertExtension = CertFindExtension (szOID_CERTIFICATE_TEMPLATE, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension))) return E_INVALIDARG; if (FALSE == CryptDecodeObject (pCertContext->dwCertEncodingType, X509_CERTIFICATE_TEMPLATE, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, NULL, &cbCertTemplateExt) || (cbCertTemplateExt == 0)) goto CryptDecodeObjectErr; pCertTemplateExt = (CERT_TEMPLATE_EXT *)LocalAlloc(LPTR, cbCertTemplateExt); if (NULL == pCertTemplateExt) goto MemoryErr; if (FALSE == CryptDecodeObject (pCertContext->dwCertEncodingType, X509_CERTIFICATE_TEMPLATE, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, (void *)(pCertTemplateExt), &cbCertTemplateExt)) goto CryptDecodeObjectErr; cbRequired = sizeof(WCHAR) * (DWORD)(strlen(pCertTemplateExt->pszObjId) + 1); // See if we're just doing a size check: if (NULL != pDataBlobProperty->pbData) { // Make sure we've allocated a large enough buffer: if (pDataBlobProperty->cbData < cbRequired) { goto MoreDataErr; } // Convert the OID to a LPWSTR: pwszOID = WideFromMB(pCertTemplateExt->pszObjId); if (NULL == pwszOID) goto WideFromMBErr; // Write the template OID to the OUT param: wcscpy((LPWSTR)pDataBlobProperty->pbData, pwszOID); } hr = S_OK; CommonReturn: // Assign the size of the OID to the cb of the OUT param. // This should be done for all code paths. pDataBlobProperty->cbData = cbRequired; // Free resources: if (NULL != pCertTemplateExt) { LocalFree(pCertTemplateExt); } if (NULL != pwszOID) { MyCoTaskMemFree(pwszOID); } return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(CryptDecodeObjectErr, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); SET_HRESULT(MoreDataErr, MY_HRESULT_FROM_WIN32(ERROR_MORE_DATA)); SET_HRESULT(WideFromMBErr, MY_HRESULT_FROM_WIN32(GetLastError())); } HRESULT getVersion(PCCERT_CONTEXT pCertContext, long *plVersion) { CERT_TEMPLATE_EXT *pCertTemplateExt = NULL; DWORD cbCertTemplateExt = 0; HRESULT hr; PCERT_EXTENSION pCertExtension = NULL; if (NULL == (pCertExtension = CertFindExtension (szOID_CERTIFICATE_TEMPLATE, pCertContext->pCertInfo->cExtension, pCertContext->pCertInfo->rgExtension))) return E_INVALIDARG; if (FALSE == CryptDecodeObject (pCertContext->dwCertEncodingType, X509_CERTIFICATE_TEMPLATE, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, NULL, &cbCertTemplateExt) || (cbCertTemplateExt == 0)) goto CryptDecodeObjectErr; pCertTemplateExt = (CERT_TEMPLATE_EXT *)LocalAlloc(LPTR, cbCertTemplateExt); if (NULL == pCertTemplateExt) goto MemoryErr; if (FALSE == CryptDecodeObject (pCertContext->dwCertEncodingType, X509_CERTIFICATE_TEMPLATE, pCertExtension->Value.pbData, pCertExtension->Value.cbData, 0, (void *)(pCertTemplateExt), &cbCertTemplateExt)) goto CryptDecodeObjectErr; *plVersion = (long)pCertTemplateExt->dwMajorVersion; hr = S_OK; CommonReturn: // Free resources: if (NULL != pCertTemplateExt) { LocalFree(pCertTemplateExt); } return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(CryptDecodeObjectErr, MY_HRESULT_FROM_WIN32(GetLastError())); SET_HRESULT(MemoryErr, E_OUTOFMEMORY); } void InitLocalScope() { dataBlob.cbData = 0; dataBlob.pbData = NULL; } void FreeLocalScope() { if (dataBlob.pbData != NULL) { LocalFree(dataBlob.pbData); } } CEnrollEndLocalScope; //------------------------------------------------------------ // // Begin procedure body. // //------------------------------------------------------------ // FIXME: index is 0 based, correct? // m_dwLastPendingRequestIndex = 0; // m_pCertContextLastEnumerated HCERTSTORE hStoreRequest = NULL; HRESULT hr = S_OK; PCCERT_CONTEXT pCertContext = NULL; // Input validiation: if (lIndex != XEPR_ENUM_FIRST && (lIndex < 0 || (ppProperty == NULL))) return E_INVALIDARG; if (0 != m_dwEnabledSafteyOptions) // not safe for scripting return E_ACCESSDENIED; // Init: local.InitLocalScope(); EnterCriticalSection(&m_csXEnroll); if ( NULL == (hStoreRequest = GetStore(StoreREQUEST)) ) goto ErrorCertOpenRequestStore; // If we're passed the ENUM_FIRST flag, reconstruct a snapshot of the request store. // if (lIndex == XEPR_ENUM_FIRST) { if (NULL != this->m_pPendingRequestTable) { delete this->m_pPendingRequestTable; } this->m_pPendingRequestTable = new PendingRequestTable; if (NULL == this->m_pPendingRequestTable) goto MemoryErr; if (S_OK != (hr = this->m_pPendingRequestTable->construct(hStoreRequest))) goto ErrorConstructPendingTable; // All done, return. goto CommonReturn; } // We want the lIndex'th element the request store. // First, ensure that the enumeration is initialized: if (NULL == m_pPendingRequestTable) goto PointerErr; // Index past the end of the table. if (this->m_pPendingRequestTable->size() <= (DWORD)lIndex) { hr = MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND); goto ErrorReturn; } pCertContext = (*this->m_pPendingRequestTable)[(DWORD)lIndex]; switch (lDesiredProperty) { case XEPR_REQUESTID: hr = local.getRequestID (pCertContext, (long *)ppProperty); break; case XEPR_CANAME: hr = local.getCAName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break; case XEPR_CAFRIENDLYNAME: hr = local.getCAFriendlyName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break; case XEPR_CADNS: hr = local.getCADNSName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break; case XEPR_DATE: hr = local.getDate (pCertContext, (PFILETIME)ppProperty); break; case XEPR_V1TEMPLATENAME: hr = local.getTemplateName (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break; case XEPR_V2TEMPLATEOID: hr = local.getTemplateOID (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break; case XEPR_VERSION: hr = local.getVersion (pCertContext, (long *)ppProperty); break; case XEPR_HASH: hr = local.getHash (pCertContext, (PCRYPT_DATA_BLOB)ppProperty); break; default: hr = E_INVALIDARG; } CommonReturn: local.FreeLocalScope(); LeaveCriticalSection(&m_csXEnroll); return hr; ErrorReturn: goto CommonReturn; SET_HRESULT(MemoryErr, E_OUTOFMEMORY); SET_HRESULT(PointerErr, E_POINTER); TRACE_ERROR(ErrorCertOpenRequestStore); TRACE_ERROR(ErrorConstructPendingTable); } HRESULT STDMETHODCALLTYPE CCEnroll::removePendingRequestWStr (IN CRYPT_DATA_BLOB thumbPrintBlob ) { EquivalentHashCertContextFilter equivHashFilter(thumbPrintBlob); PendingCertContextFilter pendingCertFilter; // combinedFilter now only allows PENDING requests which match the specified thumbprint. CompositeCertContextFilter combinedFilter(&equivHashFilter, &pendingCertFilter); HCERTSTORE hStoreRequest = NULL; HRESULT hr; PCCERT_CONTEXT pCertContext = NULL; EnterCriticalSection(&m_csXEnroll); // Input validation. if (NULL == thumbPrintBlob.pbData) { hr = E_INVALIDARG; goto ErrorReturn; } if ( NULL == (hStoreRequest = GetStore(StoreREQUEST)) ) { hr = E_UNEXPECTED; goto ErrorReturn; } if (S_OK != (hr = FilteredCertEnumCertificatesInStore (hStoreRequest, NULL, &combinedFilter, &pCertContext))) goto ErrorReturn; if (!CertDeleteCertificateFromStore(pCertContext)) { hr = MY_HRESULT_FROM_WIN32(GetLastError()); // CertDeleteCertificateFromStore *always* deletes the cert context. pCertContext = NULL; goto ErrorReturn; } pCertContext = NULL; hr = S_OK; CommonReturn: LeaveCriticalSection(&m_csXEnroll); return hr; ErrorReturn: if (pCertContext != NULL) { CertFreeCertificateContext(pCertContext); } goto CommonReturn; } HRESULT FilteredCertEnumCertificatesInStore(IN HCERTSTORE hStore, IN PCCERT_CONTEXT pCertContext, IN CertContextFilter *pFilter, OUT PCCERT_CONTEXT *pCertContextNext) { BOOL fFilterResult; HRESULT hr = S_OK; PCCERT_CONTEXT pCertContextPrev = pCertContext; while (NULL != (pCertContext = CertEnumCertificatesInStore(hStore, pCertContextPrev))) { if (S_OK != (hr = pFilter->accept(pCertContext, &fFilterResult))) return hr; if (fFilterResult) // We've found the next cert context in the filtered enumeration. { *pCertContextNext = pCertContext; return S_OK; } pCertContextPrev = pCertContext; } return MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND); } static LPVOID MyLocalAlloc(ULONG cb) { return((LPVOID) LocalAlloc(LPTR, (UINT) cb)); } static LPVOID MyLocalRealloc(LPVOID ptr, ULONG cb) { return((LPVOID) LocalReAlloc((HLOCAL) ptr, (UINT) cb, LMEM_MOVEABLE)); } static void MyLocalFree(LPVOID ptr) { LocalFree((HLOCAL) ptr); } // // From xtan, an explanation of the "no-COM" APIs: // "In early time xenroll interface IDs were not in uuid.lib so this // was a convenient C interface for people to get xenroll COM interfaces without // call CoCreateInstance. It is not in MSDN but it is in SDK headers. // I created the same API for consistency when I created ICEnroll4." // void * WINAPI PGetIEnrollNoCOM(const IID &iid) { void * pvoid = NULL; IClassFactory * pIClassFactory = NULL; HRESULT hr = S_OK; MyCoTaskMemAlloc = MyLocalAlloc; MyCoTaskMemFree = MyLocalFree; MyCoTaskMemRealloc = MyLocalRealloc; if( S_OK != (hr = DllGetClassObject(CLSID_CEnroll2, IID_IClassFactory, (void **) &pIClassFactory)) ) { pIClassFactory = NULL; } else if( S_OK != (hr = pIClassFactory->CreateInstance(NULL, iid, &pvoid)) ) { pvoid = NULL; } if(pIClassFactory != NULL) { pIClassFactory->Release(); pIClassFactory = NULL; } SetLastError(hr); return(pvoid); } IEnroll * WINAPI PIEnrollGetNoCOM(void) { return( (IEnroll *) PGetIEnrollNoCOM(IID_IEnroll) ); } IEnroll2 * WINAPI PIEnroll2GetNoCOM(void) { return( (IEnroll2 *) PGetIEnrollNoCOM(IID_IEnroll2) ); } IEnroll4 * WINAPI PIEnroll4GetNoCOM(void) { return( (IEnroll4 *) PGetIEnrollNoCOM(IID_IEnroll4) ); } HRESULT PendingRequestTable::resize(DWORD dwNewSize) { TableElem * newTable = NULL; if (dwNewSize <= 0) return E_INVALIDARG; newTable = (TableElem *)LocalAlloc(LPTR, sizeof(TableElem) * dwNewSize); if (NULL == newTable) return E_OUTOFMEMORY; if (NULL != this->table) { memcpy(newTable, this->table, this->dwElemSize * sizeof(TableElem)); LocalFree(this->table); } this->dwElemSize = dwNewSize; this->table = newTable; return S_OK; } HRESULT PendingRequestTable::add(TableElem tePendingRequest) { HRESULT hr; if (this->dwElemCount > this->dwElemSize) { return E_UNEXPECTED; } else if (this->dwElemCount == this->dwElemSize) { // Need to allocate more memory: DWORD dwNewSize = this->dwElemSize < 100 ? 100 : this->dwElemSize * 2; if (S_OK != (hr = this->resize(dwNewSize))) return hr; } this->table[this->dwElemCount++] = tePendingRequest; return S_OK; } PendingRequestTable::PendingRequestTable() : table(NULL), dwElemSize(0), dwElemCount(0) { } PendingRequestTable::~PendingRequestTable() { if (NULL != this->table) { for (DWORD dwIndex = 0; dwIndex < dwElemCount; dwIndex++) { CertFreeCertificateContext(this->table[dwIndex].pCertContext); } LocalFree(this->table); } } HRESULT PendingRequestTable::construct(HCERTSTORE hStore) { HRESULT hr = S_OK; PendingCertContextFilter pendingFilter; PCCERT_CONTEXT pCertContext = NULL; PCCERT_CONTEXT pCertContextPrev = NULL; TableElem tePendingRequest; // Enumerate all pending cert contexts, and add them to our table: for (DWORD dwIndex = 0; TRUE; dwIndex++) { if (S_OK != (hr = FilteredCertEnumCertificatesInStore (hStore, pCertContextPrev, &pendingFilter, &pCertContext))) break; tePendingRequest.pCertContext = CertDuplicateCertificateContext(pCertContext); this->add(tePendingRequest); pCertContextPrev = pCertContext; } return hr == MY_HRESULT_FROM_WIN32(CRYPT_E_NOT_FOUND) ? S_OK : hr; }