/* Copyright (c) 1997, Microsoft Corporation, all rights reserved Description: History: Nov 1997: Vijay Baliga created original version. Sep 1998: Vijay Baliga moved functions from eaptls.c and dialog.c to util.c */ #include // Required by windows.h #include // Required by windows.h #include // Required by windows.h #include // Win32 base API's #include // Required by raseapif.h #include // For RTASSERT #include // For EAPLOGONINFO #include #include #include #define SECURITY_WIN32 #include // For GetUserNameExA, CredHandle #include #include // For CredHandle #include // Required by sclogon.h #include // For SCardListReadersA #include // For ScHelperGetCertFromLogonInfo #include #include #include #include #include #include #include #define STRSAFE_NO_DEPRECATE #include extern CRITICAL_SECTION g_csProtectCachedCredentials; extern BOOL g_fCriticalSectionInitialized; /* Returns: void Notes: Used for printing EAP TLS trace statements. */ VOID EapTlsTrace( IN CHAR* Format, ... ) { va_list arglist; RTASSERT(NULL != Format); va_start(arglist, Format); TraceVprintfExA(g_dwEapTlsTraceId, 0x00010000 | TRACE_USE_MASK | TRACE_USE_MSEC, Format, arglist); va_end(arglist); } HINSTANCE GetResouceDLLHInstance( VOID ) { static HINSTANCE hResourceModule = NULL; EapTlsTrace("GetResouceDLLHInstance"); if ( !hResourceModule ) { // // Change the name of this DLL as required for each service pack // hResourceModule = LoadLibrary ( L"xpsp1res.dll"); if ( NULL == hResourceModule ) { EapTlsTrace("LoadLibraryEx failed and returned %d",GetLastError()); } } return(hResourceModule); } #if WINVER > 0x0500 DWORD CheckCallerIdentity ( HANDLE hWVTStateData ) { DWORD dwRetCode = ERROR_ACCESS_DENIED; PCRYPT_PROVIDER_DATA pProvData = NULL; PCCERT_CHAIN_CONTEXT pChainContext = NULL; PCRYPT_PROVIDER_SGNR pProvSigner = NULL; CERT_CHAIN_POLICY_PARA chainpolicyparams; CERT_CHAIN_POLICY_STATUS chainpolicystatus; if (!(pProvData = WTHelperProvDataFromStateData(hWVTStateData))) { goto done; } if (!(pProvSigner = WTHelperGetProvSignerFromChain(pProvData, 0, FALSE, 0))) { goto done; } chainpolicyparams.cbSize = sizeof(CERT_CHAIN_POLICY_PARA); // // // We do want to test for microsoft test root flags. and dont care // for revocation flags... // chainpolicyparams.dwFlags = CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG | CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG | CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS; pChainContext = pProvSigner->pChainContext; if (!CertVerifyCertificateChainPolicy ( CERT_CHAIN_POLICY_MICROSOFT_ROOT, pChainContext, &chainpolicyparams, &chainpolicystatus)) { goto done; } else { if ( S_OK == chainpolicystatus.dwError ) { dwRetCode = NO_ERROR; } else { // // Check the base policy to see if this // is a Microsoft test root // if (!CertVerifyCertificateChainPolicy ( CERT_CHAIN_POLICY_BASE, pChainContext, &chainpolicyparams, &chainpolicystatus)) { goto done; } else { if ( S_OK == chainpolicystatus.dwError ) { dwRetCode = NO_ERROR; } } } } done: return dwRetCode; } /* */ DWORD VerifyCallerTrust ( void * callersAddress ) { DWORD dwRetCode = NO_ERROR; HRESULT hr = S_OK; WINTRUST_DATA wtData; WINTRUST_FILE_INFO wtFileInfo; WINTRUST_CATALOG_INFO wtCatalogInfo; BOOL fRet = FALSE; HCATADMIN hCATAdmin = NULL; static BOOL fOKToUseTLS = FALSE; GUID guidPublishedSoftware = WINTRUST_ACTION_GENERIC_VERIFY_V2; // // Following GUID is Mirosoft's Catalog System Root // GUID guidCatSystemRoot = { 0xf750e6c3, 0x38ee, 0x11d1,{ 0x85, 0xe5, 0x0, 0xc0, 0x4f, 0xc2, 0x95, 0xee } }; HCATINFO hCATInfo = NULL; CATALOG_INFO CatInfo; HANDLE hFile = INVALID_HANDLE_VALUE; BYTE bHash[40]; DWORD cbHash = 40; MEMORY_BASIC_INFORMATION mbi; SIZE_T nbyte; DWORD nchar; wchar_t callersModule[MAX_PATH + 1]; if ( fOKToUseTLS ) { goto done; } EapTlsTrace("Verifying caller..."); nbyte = VirtualQuery( callersAddress, &mbi, sizeof(mbi) ); if (nbyte < sizeof(mbi)) { dwRetCode = ERROR_ACCESS_DENIED; EapTlsTrace("Unauthorized use of TLS attempted"); goto done; } nchar = GetModuleFileNameW( (HMODULE)(mbi.AllocationBase), callersModule, MAX_PATH ); if (nchar == 0) { dwRetCode = GetLastError(); EapTlsTrace("Unauthorized use of TLS attempted"); goto done; } // // // Try and see if WinVerifyTrust will verify // the signature as a standalone file // // ZeroMemory ( &wtData, sizeof(wtData) ); ZeroMemory ( &wtFileInfo, sizeof(wtFileInfo) ); wtData.cbStruct = sizeof(wtData); wtData.dwUIChoice = WTD_UI_NONE; wtData.fdwRevocationChecks = WTD_REVOKE_NONE; wtData.dwStateAction = WTD_STATEACTION_VERIFY; wtData.dwUnionChoice = WTD_CHOICE_FILE; wtData.pFile = &wtFileInfo; wtFileInfo.cbStruct = sizeof( wtFileInfo ); wtFileInfo.pcwszFilePath = callersModule; hr = WinVerifyTrust ( NULL, &guidPublishedSoftware, &wtData ); if ( ERROR_SUCCESS == hr ) { // // Check to see if this is indeed microsoft // signed caller // dwRetCode = CheckCallerIdentity( wtData.hWVTStateData); wtData.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifyTrust(NULL, &guidPublishedSoftware, &wtData); goto done; } wtData.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifyTrust(NULL, &guidPublishedSoftware, &wtData); // // We did not find the file was signed. // So check the system catalog to see if // the file is in the catalog and the catalog // is signed // // // Open the file // hFile = CreateFile ( callersModule, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( INVALID_HANDLE_VALUE == hFile ) { dwRetCode = GetLastError(); goto done; } fRet = CryptCATAdminAcquireContext( &hCATAdmin, &guidCatSystemRoot, 0 ); if ( !fRet ) { dwRetCode = GetLastError(); goto done; } // // Get the hash of the file here // fRet = CryptCATAdminCalcHashFromFileHandle ( hFile, &cbHash, bHash, 0 ); if ( !fRet ) { dwRetCode = GetLastError(); goto done; } ZeroMemory(&CatInfo, sizeof(CatInfo)); CatInfo.cbStruct = sizeof(CatInfo); ZeroMemory( &wtCatalogInfo, sizeof(wtCatalogInfo) ); wtData.dwUnionChoice = WTD_CHOICE_CATALOG; wtData.dwStateAction = WTD_STATEACTION_VERIFY; wtData.pCatalog = &wtCatalogInfo; wtCatalogInfo.cbStruct = sizeof(wtCatalogInfo); wtCatalogInfo.hMemberFile = hFile; wtCatalogInfo.pbCalculatedFileHash = bHash; wtCatalogInfo.cbCalculatedFileHash = cbHash; while ( ( hCATInfo = CryptCATAdminEnumCatalogFromHash ( hCATAdmin, bHash, cbHash, 0, &hCATInfo ) ) ) { if (!(CryptCATCatalogInfoFromContext(hCATInfo, &CatInfo, 0))) { // should do something (??) continue; } wtCatalogInfo.pcwszCatalogFilePath = CatInfo.wszCatalogFile; hr = WinVerifyTrust ( NULL, &guidPublishedSoftware, &wtData ); if ( ERROR_SUCCESS == hr ) { // // Verify that this file is trusted // dwRetCode = CheckCallerIdentity( wtData.hWVTStateData); wtData.dwStateAction = WTD_STATEACTION_CLOSE; WinVerifyTrust(NULL, &guidPublishedSoftware, &wtData); goto done; } } // // File not found in any of the catalogs // dwRetCode = ERROR_ACCESS_DENIED; done: if ( hCATInfo ) { CryptCATAdminReleaseCatalogContext( hCATAdmin, hCATInfo, 0 ); } if ( hCATAdmin ) { CryptCATAdminReleaseContext( hCATAdmin, 0 ); } if ( hFile ) { CloseHandle(hFile); } if ( NO_ERROR == dwRetCode ) fOKToUseTLS = TRUE; return dwRetCode; } #endif /* Returns: NO_ERROR: iff Success Notes: TraceRegister, RouterLogRegister, etc. */ extern g_CachedCreds[]; DWORD EapTlsInitialize2( IN BOOL fInitialize, IN BOOL fUI ) { static DWORD dwRefCount = 0; DWORD dwRetCode = NO_ERROR; if (fInitialize) { if (0 == dwRefCount) { ZeroMemory ( &(g_CachedCreds[0]), sizeof(g_CachedCreds[0]) ); ZeroMemory ( &(g_CachedCreds[1]), sizeof(g_CachedCreds[0]) ); if (fUI) { g_dwEapTlsTraceId = TraceRegister(L"RASTLSUI"); // // Initialize the common controls library for the controls we use. // { INITCOMMONCONTROLSEX icc; icc.dwSize = sizeof(icc); icc.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx (&icc); } } else { g_dwEapTlsTraceId = TraceRegister(L"RASTLS"); } InitializeCriticalSection( &g_csProtectCachedCredentials ); g_fCriticalSectionInitialized = TRUE; EapTlsTrace("EapTlsInitialize2"); } dwRefCount++; } else { dwRefCount--; if (0 == dwRefCount) { EapTlsTrace("EapTls[Un]Initialize2"); if (INVALID_TRACEID != g_dwEapTlsTraceId) { TraceDeregister(g_dwEapTlsTraceId); g_dwEapTlsTraceId = INVALID_TRACEID; } if ( g_fCriticalSectionInitialized ) { DeleteCriticalSection( &g_csProtectCachedCredentials ); g_fCriticalSectionInitialized = FALSE; } FreeScardDlgDll(); } } return(dwRetCode); } /* Returns: NO_ERROR: iff Success Notes: */ DWORD EapTlsInitialize( IN BOOL fInitialize ) { return EapTlsInitialize2(fInitialize, FALSE /* fUI */); } /* Returns: Notes: Obfuscate PIN in place to foil memory scans for PINs. */ VOID EncodePin( IN EAPTLS_USER_PROPERTIES* pUserProp ) { UNICODE_STRING UnicodeString; UCHAR ucSeed = 0; RtlInitUnicodeString(&UnicodeString, pUserProp->pwszPin); RtlRunEncodeUnicodeString(&ucSeed, &UnicodeString); pUserProp->usLength = UnicodeString.Length; pUserProp->usMaximumLength = UnicodeString.MaximumLength; pUserProp->ucSeed = ucSeed; } /* Returns: Notes: */ VOID DecodePin( IN EAPTLS_USER_PROPERTIES* pUserProp ) { UNICODE_STRING UnicodeString; UnicodeString.Length = pUserProp->usLength; UnicodeString.MaximumLength = pUserProp->usMaximumLength; UnicodeString.Buffer = pUserProp->pwszPin; RtlRunDecodeUnicodeString(pUserProp->ucSeed, &UnicodeString); } /* Returns: TRUE: Success FALSE: Failure Notes: Converts FileTime to a printable form in *ppwszTime. If the function returns TRUE, the caller must ultimately call LocalFree(*ppwszTime). */ BOOL FFileTimeToStr( IN FILETIME FileTime, OUT WCHAR** ppwszTime ) { SYSTEMTIME SystemTime; FILETIME LocalTime; int nBytesDate; int nBytesTime; WCHAR* pwszTemp = NULL; BOOL fRet = FALSE; RTASSERT(NULL != ppwszTime); if (!FileTimeToLocalFileTime(&FileTime, &LocalTime)) { EapTlsTrace("FileTimeToLocalFileTime(%d %d) failed and returned %d", FileTime.dwLowDateTime, FileTime.dwHighDateTime, GetLastError()); goto LDone; } if (!FileTimeToSystemTime(&LocalTime, &SystemTime)) { EapTlsTrace("FileTimeToSystemTime(%d %d) failed and returned %d", LocalTime.dwLowDateTime, LocalTime.dwHighDateTime, GetLastError()); goto LDone; } nBytesDate = GetDateFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, NULL, 0); if (0 == nBytesDate) { EapTlsTrace("GetDateFormat(%d %d %d %d %d %d %d %d) failed and " "returned %d", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, GetLastError()); goto LDone; } nBytesTime = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, NULL, 0); if (0 == nBytesTime) { EapTlsTrace("GetTimeFormat(%d %d %d %d %d %d %d %d) failed and " "returned %d", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, GetLastError()); goto LDone; } pwszTemp = LocalAlloc(LPTR, (nBytesDate + nBytesTime)*sizeof(WCHAR)); if (NULL == pwszTemp) { EapTlsTrace("LocalAlloc failed and returned %d", GetLastError()); goto LDone; } if (0 == GetDateFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, pwszTemp, nBytesDate)) { EapTlsTrace("GetDateFormat(%d %d %d %d %d %d %d %d) failed and " "returned %d", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, GetLastError()); goto LDone; } pwszTemp[nBytesDate - 1] = L' '; if (0 == GetTimeFormat(LOCALE_USER_DEFAULT, 0, &SystemTime, NULL, pwszTemp + nBytesDate, nBytesTime)) { EapTlsTrace("GetTimeFormat(%d %d %d %d %d %d %d %d) failed and " "returned %d", SystemTime.wYear, SystemTime.wMonth, SystemTime.wDayOfWeek, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, GetLastError()); goto LDone; } *ppwszTime = pwszTemp; pwszTemp = NULL; fRet = TRUE; LDone: LocalFree(pwszTemp); return(fRet); } BOOL FFormatMachineIdentity1 ( LPWSTR lpszMachineNameRaw, LPWSTR * lppszMachineNameFormatted ) { BOOL fRetVal = FALSE; LPWSTR lpwszPrefix = L"host/"; RTASSERT(NULL != lpszMachineNameRaw ); RTASSERT(NULL != lppszMachineNameFormatted ); // // Prepend host/ to the UPN name // *lppszMachineNameFormatted = (LPWSTR)LocalAlloc ( LPTR, ( wcslen ( lpszMachineNameRaw ) + wcslen ( lpwszPrefix ) + 2 ) * sizeof(WCHAR) ); if ( NULL == *lppszMachineNameFormatted ) { goto done; } wcscpy( *lppszMachineNameFormatted, lpwszPrefix ); wcscat ( *lppszMachineNameFormatted, lpszMachineNameRaw ); fRetVal = TRUE; done: return fRetVal; } /* Returns: TRUE: Success FALSE: Failure Notes: Gets the machine name from the cert as a fully qualified path hostname/path for example, hostname.redmond.microsoft.com and reformats it in the domain\hostname format. */ BOOL FFormatMachineIdentity ( LPWSTR lpszMachineNameRaw, LPWSTR * lppszMachineNameFormatted ) { BOOL fRetVal = TRUE; LPTSTR s1 = lpszMachineNameRaw; LPTSTR s2 = NULL; RTASSERT(NULL != lpszMachineNameRaw ); RTASSERT(NULL != lppszMachineNameFormatted ); //Need to add 2 more chars. One for NULL and other for $ sign *lppszMachineNameFormatted = (LPTSTR )LocalAlloc ( LPTR, (wcslen(lpszMachineNameRaw) + 2)* sizeof(WCHAR) ); if ( NULL == *lppszMachineNameFormatted ) { return FALSE; } //find the first "." and that is the identity of the machine. //the second "." is the domain. //check to see if there at least 2 dots. If not the raw string is //the output string while ( *s1 ) { if ( *s1 == '.' ) { if ( !s2 ) //First dot s2 = s1; else //second dot break; } s1++; } //can perform several additional checks here if ( *s1 != '.' ) //there are no 2 dots so raw = formatted { wcscpy ( *lppszMachineNameFormatted, lpszMachineNameRaw ); goto done; } if ( s1-s2 < 2 ) { wcscpy ( *lppszMachineNameFormatted, lpszMachineNameRaw ); goto done; } memcpy ( *lppszMachineNameFormatted, s2+1, ( s1-s2-1) * sizeof(WCHAR)); memcpy ( (*lppszMachineNameFormatted) + (s1-s2-1) , L"\\", sizeof(WCHAR)); wcsncpy ( (*lppszMachineNameFormatted) + (s1-s2), lpszMachineNameRaw, s2-lpszMachineNameRaw ); done: //Append the $ sign no matter what... wcscat ( *lppszMachineNameFormatted, L"$" ); return fRetVal; } /* Returns: TRUE: Success FALSE: Failure Notes: Gets the name in the cert pointed to by pCertContext, and converts it to a printable form in *ppwszName. If the function returns TRUE, the caller must ultimately call LocalFree(*ppwszName). */ BOOL FUserCertToStr( IN PCCERT_CONTEXT pCertContext, OUT WCHAR** ppwszName ) { DWORD dwExtensionIndex; DWORD dwAltEntryIndex; CERT_EXTENSION* pCertExtension; CERT_ALT_NAME_INFO* pCertAltNameInfo; CERT_ALT_NAME_ENTRY* pCertAltNameEntry; CERT_NAME_VALUE* pCertNameValue; DWORD dwCertAltNameInfoSize; DWORD dwCertNameValueSize; WCHAR* pwszName = NULL; BOOL fExitOuterFor; BOOL fExitInnerFor; BOOL fRet = FALSE; // See if cert has UPN in AltSubjectName->otherName fExitOuterFor = FALSE; for (dwExtensionIndex = 0; dwExtensionIndex < pCertContext->pCertInfo->cExtension; dwExtensionIndex++) { pCertAltNameInfo = NULL; pCertExtension = pCertContext->pCertInfo->rgExtension+dwExtensionIndex; if (strcmp(pCertExtension->pszObjId, szOID_SUBJECT_ALT_NAME2) != 0) { goto LOuterForEnd; } dwCertAltNameInfoSize = 0; if (!CryptDecodeObjectEx( pCertContext->dwCertEncodingType, X509_ALTERNATE_NAME, pCertExtension->Value.pbData, pCertExtension->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (VOID*)&pCertAltNameInfo, &dwCertAltNameInfoSize)) { goto LOuterForEnd; } fExitInnerFor = FALSE; for (dwAltEntryIndex = 0; dwAltEntryIndex < pCertAltNameInfo->cAltEntry; dwAltEntryIndex++) { pCertNameValue = NULL; pCertAltNameEntry = pCertAltNameInfo->rgAltEntry + dwAltEntryIndex; if ( (CERT_ALT_NAME_OTHER_NAME != pCertAltNameEntry->dwAltNameChoice) || (NULL == pCertAltNameEntry->pOtherName) || (0 != strcmp(szOID_NT_PRINCIPAL_NAME, pCertAltNameEntry->pOtherName->pszObjId))) { goto LInnerForEnd; } // We found a UPN! dwCertNameValueSize = 0; if (!CryptDecodeObjectEx( pCertContext->dwCertEncodingType, X509_UNICODE_ANY_STRING, pCertAltNameEntry->pOtherName->Value.pbData, pCertAltNameEntry->pOtherName->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (VOID*)&pCertNameValue, &dwCertNameValueSize)) { goto LInnerForEnd; } // One extra char for the terminating NULL. pwszName = LocalAlloc(LPTR, pCertNameValue->Value.cbData + sizeof(WCHAR)); if (NULL == pwszName) { EapTlsTrace("LocalAlloc failed and returned %d", GetLastError()); fExitInnerFor = TRUE; fExitOuterFor = TRUE; goto LInnerForEnd; } CopyMemory(pwszName, pCertNameValue->Value.pbData, pCertNameValue->Value.cbData); *ppwszName = pwszName; pwszName = NULL; fRet = TRUE; fExitInnerFor = TRUE; fExitOuterFor = TRUE; LInnerForEnd: LocalFree(pCertNameValue); if (fExitInnerFor) { break; } } LOuterForEnd: LocalFree(pCertAltNameInfo); if (fExitOuterFor) { break; } } LocalFree(pwszName); return(fRet); } /* Returns: TRUE: Success FALSE: Failure Notes: Gets the name in the cert pointed to by pCertContext, and converts it to a printable form in *ppwszName. If the function returns TRUE, the caller must ultimately call LocalFree(*ppwszName). */ BOOL FOtherCertToStr( IN PCCERT_CONTEXT pCertContext, IN DWORD fFlags, OUT WCHAR** ppwszName ) { WCHAR* pwszTemp = NULL; DWORD dwSize; BOOL fRet = FALSE; DWORD dwType = 0; RTASSERT(NULL != ppwszName); dwType = CERT_NAME_SIMPLE_DISPLAY_TYPE; dwSize = CertGetNameString(pCertContext,dwType , fFlags, NULL, NULL, 0); // dwSize is the number of characters, including the terminating NULL. if (dwSize <= 1) { EapTlsTrace("CertGetNameString for CERT_NAME_SIMPLE_DISPLAY_TYPE failed."); goto LDone; } pwszTemp = LocalAlloc(LPTR, dwSize*sizeof(WCHAR)); if (NULL == pwszTemp) { EapTlsTrace("LocalAlloc failed and returned %d", GetLastError()); goto LDone; } dwSize = CertGetNameString(pCertContext, dwType, fFlags, NULL, pwszTemp, dwSize); if (dwSize <= 1) { EapTlsTrace("CertGetNameString failed."); goto LDone; } *ppwszName = pwszTemp; pwszTemp = NULL; fRet = TRUE; LDone: LocalFree(pwszTemp); return(fRet); } /* Returns: TRUE: Success FALSE: Failure Notes: Special function for getting the DNS machine name from the machine auth certificate */ BOOL FMachineAuthCertToStr ( IN PCCERT_CONTEXT pCertContext, OUT WCHAR ** ppwszName ) { DWORD dwExtensionIndex; DWORD dwAltEntryIndex; CERT_EXTENSION* pCertExtension; CERT_ALT_NAME_INFO* pCertAltNameInfo; CERT_ALT_NAME_ENTRY* pCertAltNameEntry; DWORD dwCertAltNameInfoSize; WCHAR* pwszName = NULL; BOOL fExitOuterFor; BOOL fExitInnerFor; BOOL fRet = FALSE; // See if cert has UPN in AltSubjectName->otherName fExitOuterFor = FALSE; for (dwExtensionIndex = 0; dwExtensionIndex < pCertContext->pCertInfo->cExtension; dwExtensionIndex++) { pCertAltNameInfo = NULL; pCertExtension = pCertContext->pCertInfo->rgExtension+dwExtensionIndex; if (strcmp(pCertExtension->pszObjId, szOID_SUBJECT_ALT_NAME2) != 0) { goto LOuterForEnd; } dwCertAltNameInfoSize = 0; if (!CryptDecodeObjectEx( pCertContext->dwCertEncodingType, X509_ALTERNATE_NAME, pCertExtension->Value.pbData, pCertExtension->Value.cbData, CRYPT_DECODE_ALLOC_FLAG, NULL, (VOID*)&pCertAltNameInfo, &dwCertAltNameInfoSize)) { goto LOuterForEnd; } fExitInnerFor = FALSE; for (dwAltEntryIndex = 0; dwAltEntryIndex < pCertAltNameInfo->cAltEntry; dwAltEntryIndex++) { pCertAltNameEntry = pCertAltNameInfo->rgAltEntry + dwAltEntryIndex; if ( (CERT_ALT_NAME_DNS_NAME != pCertAltNameEntry->dwAltNameChoice) || (NULL == pCertAltNameEntry->pwszDNSName) ) { goto LInnerForEnd; } // We found the DNS Name! // One extra char for the terminating NULL. pwszName = LocalAlloc(LPTR, wcslen( pCertAltNameEntry->pwszDNSName ) * sizeof(WCHAR) + sizeof(WCHAR)); if (NULL == pwszName) { EapTlsTrace("LocalAlloc failed and returned %d", GetLastError()); fExitInnerFor = TRUE; fExitOuterFor = TRUE; goto LInnerForEnd; } wcscpy (pwszName, pCertAltNameEntry->pwszDNSName ); *ppwszName = pwszName; pwszName = NULL; fRet = TRUE; fExitInnerFor = TRUE; fExitOuterFor = TRUE; LInnerForEnd: if (fExitInnerFor) { break; } } LOuterForEnd: LocalFree(pCertAltNameInfo); if (fExitOuterFor) { break; } } LocalFree(pwszName); return(fRet); } /* Returns: TRUE: Success FALSE: Failure Notes: Gets the name in the cert pointed to by pCertContext, and converts it to a printable form in *ppwszName. If the function returns TRUE, the caller must ultimately call LocalFree(*ppwszName). */ BOOL FCertToStr( IN PCCERT_CONTEXT pCertContext, IN DWORD fFlags, IN BOOL fMachineCert, OUT WCHAR** ppwszName ) { if (!fMachineCert) { if (FUserCertToStr(pCertContext, ppwszName)) { return(TRUE); } } return(FOtherCertToStr(pCertContext, fFlags, ppwszName)); } #if 0 BOOL FGetIssuerOrSubject ( IN PCCERT_CONTEXT pCertContext, IN DWORD dwFlags, OUT WCHAR ** ppszNameString ) { BOOL fRet = TRUE; DWORD cbNameString =0; LPWSTR lpwszNameString = NULL; // // Get the issued to field here // cbNameString = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, NULL, lpwszNameString, 0 ); if ( 0 == cbNameString ) { EapTlsTrace("Name String Item not found"); fRet = FALSE; goto LDone; } lpwszNameString = (LPWSTR)LocalAlloc(LPTR, cbNameString ); if ( NULL == lpwszNameString ) { EapTlsTrace("Error allocing memory for name string"); fRet = FALSE; goto LDone; } cbNameString = CertGetNameString(pCertContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, dwFlags, NULL, lpwszNameString, cbNameString ); *ppszNameString = lpwszNameString; lpwszNameString = NULL; LDone: LocalFree(lpwszNameString); return fRet; } #endif /* Returns: TRUE: Success FALSE: Failure Notes: Stores the friendly name of the cert pointed to by pCertContext in *ppwszName. If the function returns TRUE, the caller must ultimately call LocalFree(*ppwszName). */ BOOL FGetFriendlyName( IN PCCERT_CONTEXT pCertContext, OUT WCHAR** ppwszName ) { WCHAR* pwszName = NULL; DWORD dwBytes; BOOL fRet = FALSE; RTASSERT(NULL != ppwszName); if (!CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, NULL, &dwBytes)) { // If there is no Friendly Name property, don't print an error stmt. goto LDone; } pwszName = LocalAlloc(LPTR, dwBytes); if (NULL == pwszName) { EapTlsTrace("LocalAlloc failed and returned %d", GetLastError()); goto LDone; } if (!CertGetCertificateContextProperty(pCertContext, CERT_FRIENDLY_NAME_PROP_ID, pwszName, &dwBytes)) { EapTlsTrace("CertGetCertificateContextProperty failed and " "returned 0x%x", GetLastError()); goto LDone; } *ppwszName = pwszName; pwszName = NULL; fRet = TRUE; LDone: LocalFree(pwszName); return(fRet); } /* Returns: TRUE iff there is a smart card reader installed. Notes: This function was provided by Doug Barlow. If 0 is used as the SCARDCONTEXT parameter, it just looks in the registry for defined readers. This will return a list of all readers ever installed on the system. To actually detect the current state of the system, we have to use a valid SCARDCONTEXT handle. */ BOOL FSmartCardReaderInstalled( VOID ) { LONG lErr; DWORD dwLen = 0; SCARDCONTEXT hCtx = 0; BOOL fReturn = FALSE; lErr = SCardListReadersA(0, NULL, NULL, &dwLen); fReturn = ( (NO_ERROR == lErr) && (2 * sizeof(CHAR) < dwLen)); if (!fReturn) { goto LDone; } fReturn = FALSE; lErr = SCardEstablishContext(SCARD_SCOPE_USER, 0, 0, &hCtx); if (SCARD_S_SUCCESS != lErr) { goto LDone; } lErr = SCardListReadersA(hCtx, NULL, NULL, &dwLen); fReturn = ( (NO_ERROR == lErr) && (2 * sizeof(CHAR) < dwLen)); LDone: if (0 != hCtx) { SCardReleaseContext(hCtx); } return(fReturn); } //Get EKU Usage Blob out of the certificate Context DWORD DwGetEKUUsage ( IN PCCERT_CONTEXT pCertContext, OUT PCERT_ENHKEY_USAGE * ppUsage ) { DWORD dwBytes = 0; DWORD dwErr = ERROR_SUCCESS; PCERT_ENHKEY_USAGE pUsage = NULL; EapTlsTrace("FGetEKUUsage"); if (!CertGetEnhancedKeyUsage(pCertContext, 0, NULL, &dwBytes)) { dwErr = GetLastError(); if (CRYPT_E_NOT_FOUND == dwErr) { EapTlsTrace("No usage in cert"); goto LDone; } EapTlsTrace("FGetEKUUsage failed and returned 0x%x", dwErr); goto LDone; } pUsage = LocalAlloc(LPTR, dwBytes); if (NULL == pUsage) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } if (!CertGetEnhancedKeyUsage(pCertContext, 0, pUsage, &dwBytes)) { dwErr = GetLastError(); EapTlsTrace("FGetEKUUsage failed and returned 0x%x", dwErr); goto LDone; } *ppUsage = pUsage; LDone: return dwErr; } /* * This functionw will check to see if the registry based cert is * a smart card cert and if the context can be opened in silent * mode. */ BOOL FCheckSCardCertAndCanOpenSilentContext ( IN PCCERT_CONTEXT pCertContext ) { PCERT_ENHKEY_USAGE pUsageInternal = NULL; BOOL fRet = TRUE; DWORD dwIndex = 0; CRYPT_KEY_PROV_INFO * pCryptKeyProvInfo = NULL; HCRYPTPROV hProv = 0; DWORD dwParam = 0; DWORD dwDataLen = 0; #if 0 // // This is not required anymore. We use CertFindChainInStore // which will make sure if private key exists... // HCRYPTPROV hProv1 = 0; #endif EapTlsTrace("FCheckSCardCertAndCanOpenSilentContext"); if ( DwGetEKUUsage ( pCertContext, &pUsageInternal) != ERROR_SUCCESS ) { goto LDone; } for (dwIndex = 0; dwIndex < pUsageInternal->cUsageIdentifier; dwIndex++) { if ( !strcmp(pUsageInternal->rgpszUsageIdentifier[dwIndex], szOID_KP_SMARTCARD_LOGON)) { EapTlsTrace("Found SCard Cert in registey. Skipping..."); goto LDone; } } // //there is no scard logon oid in the cert //So, now check to see if the csp is mixed mode // if (!CertGetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwDataLen)) { EapTlsTrace("CertGetCertificateContextProperty failed: 0x%x", GetLastError()); goto LDone; } pCryptKeyProvInfo = LocalAlloc(LPTR, dwDataLen); if (NULL == pCryptKeyProvInfo) { EapTlsTrace("Out of memory: 0x%x", GetLastError()); goto LDone; } if (!CertGetCertificateContextProperty( pCertContext, CERT_KEY_PROV_INFO_PROP_ID, pCryptKeyProvInfo, &dwDataLen)) { EapTlsTrace("CertGetCertificateContextProperty failed: 0x%x", GetLastError()); goto LDone; } EapTlsTrace( "Acquiring Context for Container Name: %ws, ProvName: %ws, ProvType 0x%x", pCryptKeyProvInfo->pwszContainerName, pCryptKeyProvInfo->pwszProvName, pCryptKeyProvInfo->dwProvType ); if (!CryptAcquireContext( &hProv, pCryptKeyProvInfo->pwszContainerName, pCryptKeyProvInfo->pwszProvName, pCryptKeyProvInfo->dwProvType, (pCryptKeyProvInfo->dwFlags & ~CERT_SET_KEY_PROV_HANDLE_PROP_ID) | CRYPT_SILENT)) { DWORD dwErr = GetLastError(); /* if ( SCARD_E_NO_SMARTCARD == dwErr ) { //This CSP requires a smart card do this is a smart //card cert in registry fRet = TRUE; } */ EapTlsTrace("CryptAcquireContext failed. This CSP cannot be opened in silent mode. skipping cert.Err: 0x%x", dwErr); goto LDone; } dwDataLen = sizeof(dwParam); if ( !CryptGetProvParam ( hProv, PP_IMPTYPE, (BYTE *)&dwParam, &dwDataLen, 0 )) { EapTlsTrace("CryptGetProvParam failed: 0x%x", GetLastError()); goto LDone; } //now check to see if CSP is MIXED if ( ( dwParam & (CRYPT_IMPL_MIXED | CRYPT_IMPL_REMOVABLE) ) == (CRYPT_IMPL_MIXED | CRYPT_IMPL_REMOVABLE) ) { EapTlsTrace("Found SCard Cert in registey. Skipping..."); goto LDone; } #if 0 // // This is not required anymore. We use CertFindChainInStore // which will make sure that private key exists... // // // Check to see if we have the private // key corresponding to this cert // if not drop this cert. if (!CryptAcquireCertificatePrivateKey( pCertContext, CRYPT_ACQUIRE_COMPARE_KEY_FLAG | CRYPT_SILENT, NULL, &hProv1, NULL, NULL )) { EapTlsTrace("Found a certificate without private key. Skipping. Error 0x%x",GetLastError()); goto LDone; } CryptReleaseContext(hProv1, 0); #endif fRet = FALSE; LDone: if ( pUsageInternal ) LocalFree(pUsageInternal); if ( pCryptKeyProvInfo ) LocalFree(pCryptKeyProvInfo); if (0 != hProv) { CryptReleaseContext(hProv, 0); } return fRet; } /* Add selected certs to the */ VOID AddCertNodeToSelList ( EAPTLS_HASH * pHash, DWORD dwNumHashes, EAPTLS_CERT_NODE * pNode, EAPTLS_CERT_NODE ** ppSelCertList, //This is an array of pointers DWORD * pdwNextSelCert ) { DWORD dw = 0; DWORD dw1 = 0; RTASSERT(NULL != pNode); EapTlsTrace("Add Selected Cert to List"); //No selected certificates if ( 0 == dwNumHashes || !ppSelCertList ) goto done; while ( dw < dwNumHashes ) { if (!memcmp(&(pNode->Hash), (pHash+ dw), sizeof(EAPTLS_HASH))) { // //check to see if the node's already in the list. //iff not then add it. Looks like there is some //problem with possible dup certs in the cert store // while ( dw1 < *pdwNextSelCert ) { if ( ! memcmp( &(*(ppSelCertList+dw1))->Hash, &(pNode->Hash), sizeof(EAPTLS_HASH) ) ) { //This is a dup node in mmc. So Skip it... goto done; } dw1++; } *( ppSelCertList + *pdwNextSelCert ) = pNode; *pdwNextSelCert = *pdwNextSelCert + 1; break; } dw++; } done: return; } /* Returns: TRUE if no enhanced key usages exist, or pCertContext has the szOID_PKIX_KP_SERVER_AUTH or szOID_PKIX_KP_CLIENT_AUTH usage depending on whether fMachine is TRUE or FALSE. Notes: */ BOOL FCheckUsage( IN PCCERT_CONTEXT pCertContext, IN PCERT_ENHKEY_USAGE pUsage, IN BOOL fMachine ) { DWORD dwIndex; DWORD dwErr; BOOL fRet = FALSE; PCERT_ENHKEY_USAGE pUsageInternal = pUsage; EapTlsTrace("FCheckUsage"); if ( NULL == pUsageInternal ) { dwErr = DwGetEKUUsage ( pCertContext, &pUsageInternal); if ( dwErr != ERROR_SUCCESS ) goto LDone; } for (dwIndex = 0; dwIndex < pUsageInternal->cUsageIdentifier; dwIndex++) { if ( ( fMachine && !strcmp(pUsageInternal->rgpszUsageIdentifier[dwIndex], szOID_PKIX_KP_SERVER_AUTH)) || ( !fMachine && !strcmp(pUsageInternal->rgpszUsageIdentifier[dwIndex], szOID_PKIX_KP_CLIENT_AUTH))) { fRet = TRUE; break; } } LDone: if ( NULL == pUsage ) { if ( pUsageInternal ) LocalFree(pUsageInternal); } return(fRet); } DWORD DwCheckCertPolicy ( IN PCCERT_CONTEXT pCertContext, OUT PCCERT_CHAIN_CONTEXT * ppCertChainContext ) { DWORD dwRetCode = ERROR_SUCCESS; LPSTR lpszEnhUsage = szOID_PKIX_KP_CLIENT_AUTH; CERT_CHAIN_PARA ChainPara; CERT_ENHKEY_USAGE EnhKeyUsage; CERT_USAGE_MATCH CertUsage; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_CHAIN_POLICY_PARA PolicyPara; CERT_CHAIN_POLICY_STATUS PolicyStatus; EapTlsTrace("FCheckPolicy"); *ppCertChainContext = NULL; ZeroMemory ( &ChainPara, sizeof(ChainPara) ); ZeroMemory ( &EnhKeyUsage, sizeof(EnhKeyUsage) ); ZeroMemory ( &CertUsage, sizeof(CertUsage) ); EnhKeyUsage.rgpszUsageIdentifier = &lpszEnhUsage; EnhKeyUsage.cUsageIdentifier = 1; EnhKeyUsage.rgpszUsageIdentifier = &lpszEnhUsage; CertUsage.dwType = USAGE_MATCH_TYPE_AND; CertUsage.Usage = EnhKeyUsage; ChainPara.cbSize = sizeof(CERT_CHAIN_PARA); ChainPara.RequestedUsage = CertUsage; if(!CertGetCertificateChain( NULL, pCertContext, NULL, pCertContext->hCertStore, &ChainPara, 0, NULL, &pChainContext)) { dwRetCode = GetLastError(); EapTlsTrace("CertGetCertificateChain failed and returned 0x%x", dwRetCode ); pChainContext = NULL; goto LDone; } ZeroMemory( &PolicyPara, sizeof(PolicyPara) ); PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.dwFlags = BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG; ZeroMemory( &PolicyStatus, sizeof(PolicyStatus) ); // // The chain already has verified the policy. // Chain context will have several bits set. // To get one error out of it, call CErtVerifyCertificateChainPolicy // if ( !CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_NT_AUTH, pChainContext, &PolicyPara, &PolicyStatus ) ) { dwRetCode = GetLastError(); EapTlsTrace( "CertVerifyCertificateChainPolicy failed. Continuing with root hash matching" "GetLastError = 0x%x.", dwRetCode); } else { // //Check to see if the policy status is good. If so, //there is no need to check for connectoid hashes any more... // if ( PolicyStatus.dwError != 0 ) { dwRetCode = PolicyStatus.dwError; EapTlsTrace( "CertVerifyCertificateChainPolicy succeeded but policy check failed 0x%x." , dwRetCode ); } else { *ppCertChainContext = pChainContext; } } LDone: if ( dwRetCode != ERROR_SUCCESS && pChainContext ) { CertFreeCertificateChain ( pChainContext ); } EapTlsTrace("FCheckPolicy done."); return dwRetCode; } /* Returns: TRUE iff the certificate is time valid. Notes: */ BOOL FCheckTimeValidity ( IN PCCERT_CONTEXT pCertContext ) { BOOL fRet = FALSE; SYSTEMTIME SysTime; FILETIME FileTime; EapTlsTrace("FCheckTimeValidity"); GetSystemTime(&SysTime); if ( !SystemTimeToFileTime ( &SysTime, &FileTime ) ) { EapTlsTrace ("Error converting from system time to file time %ld", GetLastError()); goto done; } if ( CertVerifyTimeValidity ( &FileTime, pCertContext->pCertInfo ) ) { //should return a 0 if the certificate is time valid. EapTlsTrace ( "Non Time Valid Certificate was encountered"); goto done; } fRet = TRUE; done: return fRet; } /* Returns: TRUE iff the CSP is Microsoft RSA SChannel Cryptographic Provider. Notes: */ BOOL FCheckCSP( IN PCCERT_CONTEXT pCertContext ) { DWORD dwBytes; CRYPT_KEY_PROV_INFO* pCryptKeyProvInfo = NULL; BOOL fRet = FALSE; EapTlsTrace("FCheckCSP"); if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwBytes)) { EapTlsTrace("CertGetCertificateContextProperty failed and " "returned 0x%x", GetLastError()); goto LDone; } pCryptKeyProvInfo = LocalAlloc(LPTR, dwBytes); if (NULL == pCryptKeyProvInfo) { EapTlsTrace("LocalAlloc failed and returned %d", GetLastError()); goto LDone; } if (!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_INFO_PROP_ID, pCryptKeyProvInfo, &dwBytes)) { EapTlsTrace("CertGetCertificateContextProperty failed and " "returned 0x%x", GetLastError()); goto LDone; } fRet = (PROV_RSA_SCHANNEL == pCryptKeyProvInfo->dwProvType); if ( !fRet ) { EapTlsTrace("Did not find a cert with a provider RSA_SCHANNEL or RSA_FULL"); } LDone: LocalFree(pCryptKeyProvInfo); return(fRet); } /* Returns: NO_ERROR: iff Success Notes: Gets the root cert hash of the cert represented by pCertContextServer. */ DWORD GetRootCertHashAndNameVerifyChain( IN PCERT_CONTEXT pCertContextServer, OUT EAPTLS_HASH* pHash, OUT WCHAR** ppwszName, IN BOOL fVerifyGP, OUT BOOL * pfRootCheckRequired ) { PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_CHAIN_PARA ChainPara; PCERT_SIMPLE_CHAIN pSimpleChain; PCCERT_CONTEXT pCurrentCert; DWORD dwIndex; BOOL fRootCertFound = FALSE; WCHAR* pwszName = NULL; DWORD dwErr = NO_ERROR; CERT_CHAIN_POLICY_PARA PolicyPara; CERT_CHAIN_POLICY_STATUS PolicyStatus; ZeroMemory(&ChainPara, sizeof(ChainPara)); ChainPara.cbSize = sizeof(ChainPara); *pfRootCheckRequired = TRUE; if(!CertGetCertificateChain( NULL, pCertContextServer, NULL, pCertContextServer->hCertStore, &ChainPara, 0, NULL, &pChainContext)) { dwErr = GetLastError(); EapTlsTrace("CertGetCertificateChain failed and returned 0x%x", dwErr); pChainContext = NULL; goto LDone; } //Get the hash and root cert name etc anyways... pSimpleChain = pChainContext->rgpChain[0]; for (dwIndex = 0; dwIndex < pSimpleChain->cElement; dwIndex++) { pCurrentCert = pSimpleChain->rgpElement[dwIndex]->pCertContext; if (CertCompareCertificateName(pCurrentCert->dwCertEncodingType, &pCurrentCert->pCertInfo->Issuer, &pCurrentCert->pCertInfo->Subject)) { fRootCertFound = TRUE; break; } } if (!fRootCertFound) { dwErr = ERROR_NOT_FOUND; goto LDone; } pHash->cbHash = MAX_HASH_SIZE; if (!CertGetCertificateContextProperty(pCurrentCert, CERT_HASH_PROP_ID, pHash->pbHash, &(pHash->cbHash))) { dwErr = GetLastError(); EapTlsTrace("CertGetCertificateContextProperty failed and " "returned 0x%x", dwErr); goto LDone; } if (!FCertToStr(pCurrentCert, 0, TRUE, &pwszName)) { dwErr = E_FAIL; goto LDone; } *ppwszName = pwszName; pwszName = NULL; if ( fVerifyGP ) { EapTlsTrace( "Checking against the NTAuth store to verify the certificate chain."); ZeroMemory( &PolicyPara, sizeof(PolicyPara) ); PolicyPara.cbSize = sizeof(PolicyPara); PolicyPara.dwFlags = BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG; ZeroMemory( &PolicyStatus, sizeof(PolicyStatus) ); //Authnticate against the NTAuth store and see if all's cool. if ( !CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_NT_AUTH, pChainContext, &PolicyPara, &PolicyStatus ) ) { EapTlsTrace( "CertVerifyCertificateChainPolicy failed. Continuing with root hash matching" "GetLastError = 0x%x.", GetLastError()); } else { // //Check to see if the policy status is good. If so, //there is no need to check for connectoid hashes any more... // if ( PolicyStatus.dwError != 0 ) { EapTlsTrace( "CertVerifyCertificateChainPolicy succeeded but returned 0x%x." "Continuing with root hash matching.", PolicyStatus.dwError); } else { *pfRootCheckRequired = FALSE; } } } LDone: if (pChainContext) { CertFreeCertificateChain(pChainContext); } LocalFree(pwszName); return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: Opens the EAP-TLS registry key, and returns the result in *phKeyEapTls. If the function returns NO_ERROR, the caller must ultimately call RegCloseKey(*phKeyEapTls). */ DWORD OpenEapTlsRegistryKey( IN WCHAR* pwszMachineName, IN REGSAM samDesired, OUT HKEY* phKeyEapTls ) { HKEY hKeyLocalMachine = NULL; BOOL fHKeyLocalMachineOpened = FALSE; BOOL fHKeyEapTlsOpened = FALSE; LONG lRet; DWORD dwErr = NO_ERROR; RTASSERT(NULL != phKeyEapTls); lRet = RegConnectRegistry(pwszMachineName, HKEY_LOCAL_MACHINE, &hKeyLocalMachine); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegConnectRegistry(%ws) failed and returned %d", pwszMachineName ? pwszMachineName : L"NULL", dwErr); goto LDone; } fHKeyLocalMachineOpened = TRUE; lRet = RegOpenKeyEx(hKeyLocalMachine, EAPTLS_KEY_13, 0, samDesired, phKeyEapTls); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegOpenKeyEx(%ws) failed and returned %d", EAPTLS_KEY_13, dwErr); goto LDone; } fHKeyEapTlsOpened = TRUE; LDone: if ( fHKeyEapTlsOpened && (ERROR_SUCCESS != dwErr)) { RegCloseKey(*phKeyEapTls); } if (fHKeyLocalMachineOpened) { RegCloseKey(hKeyLocalMachine); } return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: Reads/writes the server's config data. If fRead is TRUE, and the function returns NO_ERROR, LocalFree(*ppUserProp) must be called. */ DWORD ServerConfigDataIO( IN BOOL fRead, IN WCHAR* pwszMachineName, IN OUT BYTE** ppData, IN DWORD dwNumBytes ) { HKEY hKeyEapTls; EAPTLS_USER_PROPERTIES* pUserProp; BOOL fHKeyEapTlsOpened = FALSE; BYTE* pData = NULL; DWORD dwSize = 0; LONG lRet; DWORD dwType; DWORD dwErr = NO_ERROR; RTASSERT(NULL != ppData); dwErr = OpenEapTlsRegistryKey(pwszMachineName, fRead ? KEY_READ : KEY_WRITE, &hKeyEapTls); if (ERROR_SUCCESS != dwErr) { goto LDone; } fHKeyEapTlsOpened = TRUE; if (fRead) { lRet = RegQueryValueEx(hKeyEapTls, EAPTLS_VAL_SERVER_CONFIG_DATA, NULL, &dwType, NULL, &dwSize); if ( (ERROR_SUCCESS != lRet) || (REG_BINARY != dwType) || (sizeof(EAPTLS_USER_PROPERTIES) != dwSize)) { pData = LocalAlloc(LPTR, sizeof(EAPTLS_USER_PROPERTIES)); if (NULL == pData) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } pUserProp = (EAPTLS_USER_PROPERTIES*)pData; pUserProp->dwVersion = 0; } else { pData = LocalAlloc(LPTR, dwSize); if (NULL == pData) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } lRet = RegQueryValueEx(hKeyEapTls, EAPTLS_VAL_SERVER_CONFIG_DATA, NULL, &dwType, pData, &dwSize); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegQueryValueEx(%ws) failed and returned %d", EAPTLS_VAL_SERVER_CONFIG_DATA, dwErr); goto LDone; } } pUserProp = (EAPTLS_USER_PROPERTIES*)pData; pUserProp->dwSize = sizeof(EAPTLS_USER_PROPERTIES); pUserProp->awszString[0] = 0; *ppData = pData; pData = NULL; } else { lRet = RegSetValueEx(hKeyEapTls, EAPTLS_VAL_SERVER_CONFIG_DATA, 0, REG_BINARY, *ppData, dwNumBytes); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegSetValueEx(%ws) failed and returned %d", EAPTLS_VAL_SERVER_CONFIG_DATA, dwErr); goto LDone; } } LDone: if (fHKeyEapTlsOpened) { RegCloseKey(hKeyEapTls); } LocalFree(pData); return(dwErr); } /* Returns: VOID Notes: */ VOID FreeCertList( IN EAPTLS_CERT_NODE* pNode ) { while (NULL != pNode) { LocalFree(pNode->pwszDisplayName); LocalFree(pNode->pwszFriendlyName); LocalFree(pNode->pwszIssuer); LocalFree(pNode->pwszExpiration); pNode = pNode->pNext; } } /* Returns: VOID Notes: Creates a linked list of certs from the pwszStoreName store. This list is created in *ppCertList. *ppCert is made to point to the cert whose hash is the same as the hash in *pHash. The linked list must eventually be freed by calling FreeCertList. */ VOID CreateCertList( IN BOOL fServer, IN BOOL fRouter, IN BOOL fRoot, OUT EAPTLS_CERT_NODE** ppCertList, OUT EAPTLS_CERT_NODE** ppCert, //This is an array of pointers... IN DWORD dwNumHashes, IN EAPTLS_HASH* pHash, //This is an array of hashes... IN WCHAR* pwszStoreName ) { HCERTSTORE hCertStore = NULL; EAPTLS_CERT_NODE* pCertList = NULL; EAPTLS_CERT_NODE* pCert = NULL; EAPTLS_CERT_NODE* pLastNode = NULL; PCCERT_CONTEXT pCertContext; BOOL fExitWhile; EAPTLS_CERT_NODE* pNode; DWORD dwErr = NO_ERROR; DWORD dwNextSelCert = 0; PCCERT_CHAIN_CONTEXT pChainContext = NULL; CERT_CHAIN_FIND_BY_ISSUER_PARA FindPara; RTASSERT(NULL != ppCertList); hCertStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, 0, 0, CERT_STORE_READONLY_FLAG | ((fServer || fRouter) ? CERT_SYSTEM_STORE_LOCAL_MACHINE : CERT_SYSTEM_STORE_CURRENT_USER), pwszStoreName); if (NULL == hCertStore) { dwErr = GetLastError(); EapTlsTrace("CertOpenSystemStore failed and returned 0x%x", dwErr); goto LDone; } //Changed from fRoot||fServer to fRoot only. if (fRoot) { pCertList = LocalAlloc(LPTR, sizeof(EAPTLS_CERT_NODE)); if (NULL == pCertList) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } pLastNode = pCertList; } fExitWhile = FALSE; pCertContext = NULL; ZeroMemory ( &FindPara, sizeof(FindPara) ); FindPara.cbSize = sizeof(FindPara); FindPara.pszUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH; while (!fExitWhile) { dwErr = NO_ERROR; pNode = NULL; /* The returned pointer is freed when passed as the pPrevCertContext on a subsequent call. Otherwise, the pointer must be freed by calling CertFreeCertificateContext. A pPrevCertContext that is not NULL is always freed by this function (through a call to CertFreeCertificateContext), even for an error. */ if ( fRoot || fRouter || fServer ) { pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext); if (NULL == pCertContext) { fExitWhile = TRUE; goto LWhileEnd; } if ( !fRoot && !FCheckUsage(pCertContext, NULL, fServer)) { goto LWhileEnd; } } else { // // Use CertFindChainInStore to get to the certificate // pChainContext = CertFindChainInStore ( hCertStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0, CERT_CHAIN_FIND_BY_ISSUER, &FindPara, pChainContext ); if ( NULL == pChainContext ) { fExitWhile = TRUE; goto LWhileEnd; } //Set the cert context to appropriate value pCertContext = pChainContext->rgpChain[0]->rgpElement[0]->pCertContext; } // //Skip if it is smart card cached certificate //or we cannot open this csp in silent mode //This is done iff it is not root certs and server // if ( !fRoot && !fServer && FCheckSCardCertAndCanOpenSilentContext ( pCertContext ) ) { goto LWhileEnd; } if ( !FCheckTimeValidity(pCertContext ) ) { goto LWhileEnd; } if ( fServer && !FCheckCSP(pCertContext)) { goto LWhileEnd; } pNode = LocalAlloc(LPTR, sizeof(EAPTLS_CERT_NODE)); if (NULL == pNode) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); fExitWhile = TRUE; goto LWhileEnd; } FGetFriendlyName(pCertContext, &(pNode->pwszFriendlyName)); // // If there is no UPN name, this cert will be skipped here // if ( !FCertToStr(pCertContext, 0, fServer || fRouter, &(pNode->pwszDisplayName)) || !FCertToStr(pCertContext, CERT_NAME_ISSUER_FLAG, TRUE, &(pNode->pwszIssuer)) || !FFileTimeToStr(pCertContext->pCertInfo->NotAfter, &(pNode->pwszExpiration))) { goto LWhileEnd; } pNode->Hash.cbHash = MAX_HASH_SIZE; if (!CertGetCertificateContextProperty( pCertContext, CERT_HASH_PROP_ID, pNode->Hash.pbHash, &(pNode->Hash.cbHash))) { dwErr = GetLastError(); EapTlsTrace("CertGetCertificateContextProperty failed and " "returned 0x%x", dwErr); fExitWhile = TRUE; goto LWhileEnd; } #if 0 // This is not being used anywhere. So dont worry about it. // // Get Issuer and subject information // FGetIssuerOrSubject ( pCertContext, 0, &(pNode->pwszIssuedTo) ); FGetIssuerOrSubject ( pCertContext, CERT_NAME_ISSUER_FLAG, &(pNode->pwszIssuedBy) ); #endif // // Finally copy the issued date into the structure // CopyMemory( &pNode->IssueDate, &pCertContext->pCertInfo->NotBefore, sizeof(FILETIME) ); if (NULL == pLastNode) { pCertList = pLastNode = pNode; } else { pLastNode->pNext = pNode; pLastNode = pNode; } //Check if the hash for current node is in the list //that has been passed to us AddCertNodeToSelList ( pHash, dwNumHashes, pNode, ppCert, //This is an array of pointers &dwNextSelCert ); pNode = NULL; LWhileEnd: if (NULL != pNode) { LocalFree(pNode->pwszDisplayName); LocalFree(pNode->pwszFriendlyName); LocalFree(pNode->pwszIssuer); LocalFree(pNode->pwszExpiration); LocalFree(pNode); pNode = NULL; } if ( fRoot || fRouter ) { if ( fExitWhile && (NULL != pCertContext)) { CertFreeCertificateContext(pCertContext); // Always returns TRUE; } } else { if ( fExitWhile && ( NULL != pChainContext ) ) { CertFreeCertificateChain(pChainContext); } } } // If we couldn't find an appropriate default cert, make the first // cert (if there is one) the default if (NULL == pCert) { pCert = pCertList; } LDone: if (NO_ERROR != dwErr) { FreeCertList(pCertList); } else { *ppCertList = pCertList; } if (NULL != hCertStore) { if (!CertCloseStore(hCertStore, 0)) { EapTlsTrace("CertCloseStore failed and returned 0x%x", GetLastError()); } } } DWORD GetLocalMachineName ( OUT WCHAR ** ppLocalMachineName ) { DWORD dwRetCode = NO_ERROR; WCHAR * pLocalMachineName = NULL; DWORD dwLocalMachineNameLen = 0; if ( !GetComputerNameEx ( ComputerNameDnsFullyQualified, pLocalMachineName, &dwLocalMachineNameLen ) ) { dwRetCode = GetLastError(); if ( ERROR_MORE_DATA != dwRetCode ) goto LDone; dwRetCode = NO_ERROR; } pLocalMachineName = (WCHAR *)LocalAlloc( LPTR, (dwLocalMachineNameLen * sizeof(WCHAR)) + sizeof(WCHAR) ); if ( NULL == pLocalMachineName ) { dwRetCode = GetLastError(); goto LDone; } if ( !GetComputerNameEx ( ComputerNameDnsFullyQualified, pLocalMachineName, &dwLocalMachineNameLen ) ) { dwRetCode = GetLastError(); goto LDone; } *ppLocalMachineName = pLocalMachineName; pLocalMachineName = NULL; LDone: LocalFree(pLocalMachineName); return dwRetCode; } /* Returns: NO_ERROR: iff Success Notes: If this function returns NO_ERROR, CertFreeCertificateContext(*ppCertContext) must be called. */ DWORD GetDefaultClientMachineCert( IN HCERTSTORE hCertStore, OUT PCCERT_CONTEXT* ppCertContext ) { CTL_USAGE CtlUsage; CHAR* szUsageIdentifier; PCCERT_CONTEXT pCertContext = NULL; EAPTLS_HASH FirstCertHash; //This is the hash of first cert //with client auth found in the store PCCERT_CONTEXT pCertContextPrev = NULL; //Previous context in the search EAPTLS_HASH SelectedCertHash; //Hash of the certificate last selected FILETIME SelectedCertNotBefore; //Not Before date of last selected EAPTLS_HASH TempHash; //Scratch variable WCHAR * pwszIdentity = NULL; //Machine Name in the cert WCHAR * pLocalMachineName = NULL; //Local Machine Name DWORD dwErr = NO_ERROR; BOOL fGotIdentity; CRYPT_HASH_BLOB HashBlob; EapTlsTrace("GetDefaultClientMachineCert"); RTASSERT(NULL != ppCertContext); ZeroMemory( &SelectedCertHash, sizeof(SelectedCertHash) ); ZeroMemory( &SelectedCertNotBefore, sizeof(SelectedCertNotBefore) ); *ppCertContext = NULL; dwErr = GetLocalMachineName ( &pLocalMachineName ); if ( NO_ERROR != dwErr ) { EapTlsTrace("Error getting LocalMachine Name 0x%x", dwErr); goto LDone; } szUsageIdentifier = szOID_PKIX_KP_CLIENT_AUTH; CtlUsage.cUsageIdentifier = 1; CtlUsage.rgpszUsageIdentifier = &szUsageIdentifier; pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_ENHKEY_USAGE, &CtlUsage, NULL); if ( NULL == pCertContext ) { dwErr = GetLastError(); EapTlsTrace("CertFindCertificateInStore failed and returned 0x%x", dwErr); if ( CRYPT_E_NOT_FOUND == dwErr ) { dwErr = ERROR_NO_EAPTLS_CERTIFICATE; } goto LDone; } FirstCertHash.cbHash = MAX_HASH_SIZE; // //Store the hash of first cert. In case we dont find any cert that exactly matches //the filtering, we need to use this. if (!CertGetCertificateContextProperty( pCertContext, CERT_HASH_PROP_ID, FirstCertHash.pbHash, &(FirstCertHash.cbHash) ) ) { dwErr = GetLastError(); EapTlsTrace("CertGetCertificateContextProperty failed and " "returned 0x%x", dwErr); goto LDone; } do { //Check time validity of the cert. if ( !FCheckTimeValidity( pCertContext) ) { //cert expired. So skip it EapTlsTrace("Found expired Cert. Skipping this cert."); goto LWhileEnd; } fGotIdentity = FALSE; // //Get the subject Alt Name // if ( FMachineAuthCertToStr(pCertContext, &pwszIdentity) ) { fGotIdentity = TRUE; } else { EapTlsTrace("Could not get identity from subject alt name."); if ( FCertToStr(pCertContext, 0, TRUE, &pwszIdentity)) { fGotIdentity = TRUE; } } if ( fGotIdentity ) { // //Check to see if this is the same identity as this machine // if ( !_wcsicmp ( pwszIdentity, pLocalMachineName ) ) { // //Store the hash of cert. TempHash.cbHash = MAX_HASH_SIZE; if (!CertGetCertificateContextProperty( pCertContext, CERT_HASH_PROP_ID, TempHash.pbHash, &(TempHash.cbHash) ) ) { EapTlsTrace("CertGetCertificateContextProperty failed and " "returned 0x%x. Skipping this certificate", GetLastError()); goto LWhileEnd; } // //Got a cert so if there is already a cert selected, //compare the file time of this cert with the one //already selected. If this is more recent, use this //one. // if ( SelectedCertHash.cbHash ) { if ( CompareFileTime( &SelectedCertNotBefore, &(pCertContext->pCertInfo->NotBefore) ) < 0 ) { //Got a newer cert so replace the old cert with new one CopyMemory ( &SelectedCertHash, &TempHash, sizeof(SelectedCertHash) ); CopyMemory ( &SelectedCertNotBefore, &(pCertContext->pCertInfo->NotBefore), sizeof( SelectedCertNotBefore ) ); } } else { // //This is the first cert. So copy over the hash and //file time. CopyMemory ( &SelectedCertHash, &TempHash, sizeof(SelectedCertHash) ); CopyMemory ( &SelectedCertNotBefore, &(pCertContext->pCertInfo->NotBefore), sizeof( SelectedCertNotBefore ) ); } } else { EapTlsTrace("Could not get identity from the cert. skipping this cert."); } } else { EapTlsTrace("Could not get identity from the cert. skipping this cert."); } LWhileEnd: pCertContextPrev = pCertContext; if ( pwszIdentity ) { LocalFree ( pwszIdentity ); pwszIdentity = NULL; } //Get the next certificate. pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_ENHKEY_USAGE, &CtlUsage, pCertContextPrev ); }while ( pCertContext ); // //Now that we have enumerated all the certs, //check to see if we have a selected cert. If no selected //cert is present, send back the first cert. // if ( SelectedCertHash.cbHash ) { EapTlsTrace("Found Machine Cert based on machinename, client auth, time validity."); HashBlob.cbData = SelectedCertHash.cbHash; HashBlob.pbData = SelectedCertHash.pbHash; } else { EapTlsTrace("Did not find Machine Cert based on the given machinename, client auth, time validity. Using the first cert with Client Auth OID."); HashBlob.cbData = FirstCertHash.cbHash; HashBlob.pbData = FirstCertHash.pbHash; } *ppCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_HASH, &HashBlob, NULL); if (NULL == *ppCertContext) { dwErr = GetLastError(); EapTlsTrace("CertFindCertificateInStore failed with 0x%x.", dwErr); if ( CRYPT_E_NOT_FOUND == dwErr ) { dwErr = ERROR_NO_EAPTLS_CERTIFICATE; } } LDone: LocalFree (pLocalMachineName); LocalFree (pwszIdentity); if ( NO_ERROR != dwErr ) { if ( pCertContext ) { CertFreeCertificateContext( pCertContext ); } } EapTlsTrace("GetDefaultClientMachineCert done."); return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: If this function returns NO_ERROR, CertFreeCertificateContext(*ppCertContext) must be called. */ DWORD GetDefaultMachineCert( IN HCERTSTORE hCertStore, OUT PCCERT_CONTEXT* ppCertContext ) { CTL_USAGE CtlUsage; CHAR* szUsageIdentifier; PCCERT_CONTEXT pCertContext; DWORD dwErr = NO_ERROR; EapTlsTrace("GetDefaultMachineCert"); RTASSERT(NULL != ppCertContext); *ppCertContext = NULL; szUsageIdentifier = szOID_PKIX_KP_SERVER_AUTH; CtlUsage.cUsageIdentifier = 1; CtlUsage.rgpszUsageIdentifier = &szUsageIdentifier; pCertContext = CertFindCertificateInStore(hCertStore, X509_ASN_ENCODING, 0, CERT_FIND_ENHKEY_USAGE, &CtlUsage, NULL); if (NULL == pCertContext) { dwErr = GetLastError(); EapTlsTrace("CertFindCertificateInStore failed and returned 0x%x", dwErr); goto LDone; } *ppCertContext = pCertContext; LDone: return(dwErr); } /* Returns: Notes: Stolen from \private\windows\gina\msgina\wlsec.c */ VOID RevealPassword( IN UNICODE_STRING* pHiddenPassword ) { SECURITY_SEED_AND_LENGTH* SeedAndLength; UCHAR Seed; SeedAndLength = (SECURITY_SEED_AND_LENGTH*)&pHiddenPassword->Length; Seed = SeedAndLength->Seed; SeedAndLength->Seed = 0; RtlRunDecodeUnicodeString(Seed, pHiddenPassword); } DWORD GetMBytePIN ( WCHAR * pwszPIN, CHAR ** ppszPIN ) { DWORD count = 0; CHAR * pszPin = NULL; DWORD dwErr = NO_ERROR; count = WideCharToMultiByte( CP_UTF8, 0, pwszPIN, -1, NULL, 0, NULL, NULL); if (0 == count) { dwErr = GetLastError(); EapTlsTrace("WideCharToMultiByte failed: %d", dwErr); goto LDone; } pszPin = LocalAlloc(LPTR, count); if (NULL == pszPin) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed: 0x%x", dwErr); goto LDone; } count = WideCharToMultiByte( CP_UTF8, 0, pwszPIN, -1, pszPin, count, NULL, NULL); if (0 == count) { dwErr = GetLastError(); EapTlsTrace("WideCharToMultiByte failed: %d", dwErr); goto LDone; } *ppszPIN = pszPin; LDone: if ( NO_ERROR != dwErr ) { if ( pszPin ) LocalFree(pszPin); } return dwErr; } /* Returns: NO_ERROR: iff Success Notes: */ DWORD GetCertFromLogonInfo( IN BYTE* pUserDataIn, IN DWORD dwSizeOfUserDataIn, OUT PCCERT_CONTEXT* ppCertContext ) { EAPLOGONINFO* pEapLogonInfo = (EAPLOGONINFO*)pUserDataIn; BYTE* pbLogonInfo = NULL; BYTE* pbPinInfo; WCHAR* wszPassword = NULL; CHAR* pszPIN = NULL; //Multibyte Version of the PIN UNICODE_STRING UnicodeString; PCCERT_CONTEXT pCertContext = NULL; BOOL fInitialized = FALSE; NTSTATUS Status; DWORD dwErr = NO_ERROR; CERT_KEY_CONTEXT stckContext; DWORD cbstckContext= sizeof(CERT_KEY_CONTEXT); EapTlsTrace("GetCertFromLogonInfo"); RTASSERT(NULL != ppCertContext); *ppCertContext = NULL; if ( 0 == pEapLogonInfo->dwLogonInfoSize || 0 == pEapLogonInfo->dwPINInfoSize || 0 == dwSizeOfUserDataIn) { dwErr = E_FAIL; goto LDone; } pbLogonInfo = LocalAlloc(LPTR, pEapLogonInfo->dwLogonInfoSize); if (NULL == pbLogonInfo) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } CopyMemory(pbLogonInfo, (BYTE*)pEapLogonInfo + pEapLogonInfo->dwOffsetLogonInfo, pEapLogonInfo->dwLogonInfoSize); pbPinInfo = (BYTE*)pEapLogonInfo + pEapLogonInfo->dwOffsetPINInfo; wszPassword = LocalAlloc(LPTR, pEapLogonInfo->dwPINInfoSize); if (NULL == wszPassword) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } CopyMemory(wszPassword, pbPinInfo + 2 * sizeof(USHORT), pEapLogonInfo->dwPINInfoSize - 2 * sizeof(USHORT)); UnicodeString.Length = *((USHORT*)pbPinInfo); UnicodeString.MaximumLength = *((USHORT*)pbPinInfo + 1); UnicodeString.Buffer = wszPassword; Status = ScHelperInitializeContext(pbLogonInfo, pEapLogonInfo->dwLogonInfoSize); if (STATUS_SUCCESS != Status) { dwErr = Status; EapTlsTrace("ScHelperInitializeContext failed and returned 0x%x", dwErr); goto LDone; } fInitialized = TRUE; RevealPassword(&UnicodeString); Status = ScHelperGetCertFromLogonInfo(pbLogonInfo, &UnicodeString, &pCertContext); if (STATUS_SUCCESS != Status) { dwErr = Status; EapTlsTrace("ScHelperGetCertFromLogonInfo failed and returned 0x%x", dwErr); goto LDone; } //BUGID: 260728 - ScHelperGetCertFromLogonInfo does not associate the PIN // with certificate context. Hence the following lines of code are needed // to do the needful. if ( ! CertGetCertificateContextProperty ( pCertContext, CERT_KEY_CONTEXT_PROP_ID, &stckContext, &cbstckContext ) ) { dwErr = Status = GetLastError(); EapTlsTrace ("CertGetCertificateContextProperty failed and returned 0x%x", dwErr ); goto LDone; } dwErr = GetMBytePIN ( wszPassword, &pszPIN ); if ( dwErr != NO_ERROR ) { goto LDone; } if (!CryptSetProvParam( stckContext.hCryptProv, PP_KEYEXCHANGE_PIN, pszPIN, 0)) { dwErr = GetLastError(); EapTlsTrace("CryptSetProvParam failed: 0x%x", dwErr); ZeroMemory(pszPIN, strlen(pszPIN)); goto LDone; } // Zero the entire allocated buffer. ZeroMemory(wszPassword, pEapLogonInfo->dwPINInfoSize); ZeroMemory(pszPIN, strlen(pszPIN)); *ppCertContext = pCertContext; pCertContext = NULL; LDone: if (fInitialized) { ScHelperRelease(pbLogonInfo); } if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); // Always returns TRUE; } LocalFree(wszPassword); LocalFree(pbLogonInfo); if ( pszPIN ) LocalFree ( pszPIN ); return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: If this function returns TRUE, LocalFree(*ppwszIdentity) must be called. */ DWORD GetIdentityFromLogonInfo( IN BYTE* pUserDataIn, IN DWORD dwSizeOfUserDataIn, OUT WCHAR** ppwszIdentity ) { WCHAR* pwszIdentity = NULL; PCCERT_CONTEXT pCertContext = NULL; DWORD dwErr = NO_ERROR; RTASSERT(NULL != pUserDataIn); RTASSERT(NULL != ppwszIdentity); *ppwszIdentity = NULL; dwErr = GetCertFromLogonInfo(pUserDataIn, dwSizeOfUserDataIn, &pCertContext); if (NO_ERROR != dwErr) { goto LDone; } if (FCertToStr(pCertContext, 0, FALSE, &pwszIdentity)) { EapTlsTrace("(logon info) The name in the certificate is: %ws", pwszIdentity); *ppwszIdentity = pwszIdentity; pwszIdentity = NULL; } LDone: LocalFree(pwszIdentity); if (NULL != pCertContext) { CertFreeCertificateContext(pCertContext); // Always returns TRUE; } return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: There are two types of structures that can come in: 1. Version 0 structure which comes in as a a part of CM profile created on w2k or as a part of a connectoid that gor upgraded from w2k We change the data structure to new v1 data structure here 2. Get a version 1 structure and it is all cool. Note that the first x bytes of version 1 data structure are exactly the same as version 0. */ DWORD ReadConnectionData( IN BOOL fWireless, IN BYTE* pConnectionDataIn, IN DWORD dwSizeOfConnectionDataIn, OUT EAPTLS_CONN_PROPERTIES** ppConnProp ) { DWORD dwErr = NO_ERROR; EAPTLS_CONN_PROPERTIES* pConnProp = NULL; EAPTLS_CONN_PROPERTIES* pConnPropv1 = NULL; RTASSERT(NULL != ppConnProp); if ( dwSizeOfConnectionDataIn < sizeof(EAPTLS_CONN_PROPERTIES) ) { pConnProp = LocalAlloc(LPTR, sizeof(EAPTLS_CONN_PROPERTIES) + sizeof(EAPTLS_CONN_PROPERTIES_V1_EXTRA)); if (NULL == pConnProp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } //This is a new structure pConnProp->dwVersion = 2; pConnProp->dwSize = sizeof(EAPTLS_CONN_PROPERTIES); if ( fWireless ) { // // Set the defaults appropriately // pConnProp->fFlags |= EAPTLS_CONN_FLAG_REGISTRY; pConnProp->fFlags |= EAPTLS_CONN_FLAG_SIMPLE_CERT_SEL; pConnProp->fFlags |= EAPTLS_CONN_FLAG_NO_VALIDATE_NAME; } } else { RTASSERT(NULL != pConnectionDataIn); // //Check to see if this is a version 0 structure //If it is a version 0 structure then we migrate it to version1 // pConnProp = LocalAlloc(LPTR, dwSizeOfConnectionDataIn); if (NULL == pConnProp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } // If the user has mucked with the phonebook, we mustn't be affected. // The size must be correct. CopyMemory(pConnProp, pConnectionDataIn, dwSizeOfConnectionDataIn); pConnProp->dwSize = dwSizeOfConnectionDataIn; // // The Unicode string must be NULL terminated. // /* ((BYTE*)pConnProp)[dwSizeOfConnectionDataIn - 2] = 0; ((BYTE*)pConnProp)[dwSizeOfConnectionDataIn - 1] = 0; */ pConnPropv1 = LocalAlloc(LPTR, dwSizeOfConnectionDataIn + sizeof(EAPTLS_CONN_PROPERTIES_V1_EXTRA) ); if ( NULL == pConnPropv1 ) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed while allocating v1 structure and returned %d", dwErr ); goto LDone; } CopyMemory ( pConnPropv1, pConnProp, dwSizeOfConnectionDataIn); // //Check to see if the original struct has hash set // /* if ( pConnProp->Hash.cbHash ) { ConnPropSetNumHashes( pConnPropv1, 1 ); } */ if ( 2 != pConnPropv1->dwVersion ) { if ( pConnPropv1->fFlags & EAPTLS_CONN_FLAG_REGISTRY ) { pConnPropv1->fFlags |= EAPTLS_CONN_FLAG_SIMPLE_CERT_SEL; } pConnPropv1->dwVersion = 2; } LocalFree ( pConnProp ); pConnProp = pConnPropv1; pConnPropv1 = NULL; } *ppConnProp = pConnProp; pConnProp = NULL; LDone: LocalFree(pConnProp); LocalFree(pConnPropv1); return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: */ DWORD ReadUserData( IN BYTE* pUserDataIn, IN DWORD dwSizeOfUserDataIn, OUT EAPTLS_USER_PROPERTIES** ppUserProp ) { DWORD dwErr = NO_ERROR; EAPTLS_USER_PROPERTIES* pUserProp = NULL; RTASSERT(NULL != ppUserProp); if (dwSizeOfUserDataIn < sizeof(EAPTLS_USER_PROPERTIES)) { pUserProp = LocalAlloc(LPTR, sizeof(EAPTLS_USER_PROPERTIES)); if (NULL == pUserProp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } pUserProp->dwVersion = 0; pUserProp->dwSize = sizeof(EAPTLS_USER_PROPERTIES); pUserProp->pwszDiffUser = pUserProp->awszString; pUserProp->dwPinOffset = 0; pUserProp->pwszPin = pUserProp->awszString + pUserProp->dwPinOffset; } else { RTASSERT(NULL != pUserDataIn); pUserProp = LocalAlloc(LPTR, dwSizeOfUserDataIn); if (NULL == pUserProp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } CopyMemory(pUserProp, pUserDataIn, dwSizeOfUserDataIn); // If someone has mucked with the registry, we mustn't // be affected. pUserProp->dwSize = dwSizeOfUserDataIn; pUserProp->pwszDiffUser = pUserProp->awszString; pUserProp->pwszPin = pUserProp->awszString + pUserProp->dwPinOffset; } *ppUserProp = pUserProp; pUserProp = NULL; LDone: LocalFree(pUserProp); return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: */ DWORD AllocUserDataWithNewIdentity( IN EAPTLS_USER_PROPERTIES* pUserProp, IN WCHAR* pwszIdentity, OUT EAPTLS_USER_PROPERTIES** ppUserProp ) { DWORD dwNumChars; EAPTLS_USER_PROPERTIES* pUserPropTemp = NULL; DWORD dwSize; DWORD dwErr = NO_ERROR; *ppUserProp = NULL; dwNumChars = wcslen(pwszIdentity); dwSize = sizeof(EAPTLS_USER_PROPERTIES) + (dwNumChars + wcslen(pUserProp->pwszPin) + 1) * sizeof(WCHAR); pUserPropTemp = LocalAlloc(LPTR, dwSize); if (NULL == pUserPropTemp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } CopyMemory(pUserPropTemp, pUserProp, sizeof(EAPTLS_USER_PROPERTIES)); pUserPropTemp->dwSize = dwSize; pUserPropTemp->pwszDiffUser = pUserPropTemp->awszString; wcscpy(pUserPropTemp->pwszDiffUser, pwszIdentity); pUserPropTemp->dwPinOffset = dwNumChars + 1; pUserPropTemp->pwszPin = pUserPropTemp->awszString + pUserPropTemp->dwPinOffset; wcscpy(pUserPropTemp->pwszPin, pUserProp->pwszPin); *ppUserProp = pUserPropTemp; pUserPropTemp = NULL; ZeroMemory(pUserProp, pUserProp->dwSize); LDone: LocalFree(pUserPropTemp); return(dwErr); } /* Returns: NO_ERROR: iff Success Notes: */ DWORD AllocUserDataWithNewPin( IN EAPTLS_USER_PROPERTIES* pUserProp, IN PBYTE pbPin, IN DWORD cbPin, OUT EAPTLS_USER_PROPERTIES** ppUserProp ) { DWORD dwNumChars; EAPTLS_USER_PROPERTIES* pUserPropTemp = NULL; DWORD dwSize; DWORD dwErr = NO_ERROR; *ppUserProp = NULL; dwNumChars = wcslen(pUserProp->pwszDiffUser); dwSize = sizeof(EAPTLS_USER_PROPERTIES) + (dwNumChars + 1 ) * sizeof(WCHAR) + cbPin; pUserPropTemp = LocalAlloc(LPTR, dwSize); if (NULL == pUserPropTemp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } CopyMemory(pUserPropTemp, pUserProp, sizeof(EAPTLS_USER_PROPERTIES)); pUserPropTemp->dwSize = dwSize; pUserPropTemp->pwszDiffUser = pUserPropTemp->awszString; wcscpy(pUserPropTemp->pwszDiffUser, pUserProp->pwszDiffUser); pUserPropTemp->dwPinOffset = dwNumChars + 1; pUserPropTemp->pwszPin = pUserPropTemp->awszString + pUserPropTemp->dwPinOffset; CopyMemory(pUserPropTemp->pwszPin, pbPin, cbPin); *ppUserProp = pUserPropTemp; pUserPropTemp = NULL; ZeroMemory(pUserProp, pUserProp->dwSize); LDone: LocalFree(pUserPropTemp); return(dwErr); } /* Returns: Notes: String resource message loader routine. Returns the address of a string corresponding to string resource dwStringId or NULL if error. It is caller's responsibility to LocalFree the returned string. */ WCHAR* WszFromId( IN HINSTANCE hInstance, IN DWORD dwStringId ) { WCHAR* wszBuf = NULL; int cchBuf = 256; int cchGot; for (;;) { wszBuf = LocalAlloc(LPTR, cchBuf * sizeof(WCHAR)); if (NULL == wszBuf) { break; } /* LoadString wants to deal with character-counts rather than byte-counts...weird. Oh, and if you're thinking I could FindResource then SizeofResource to figure out the string size, be advised it doesn't work. From perusing the LoadString source, it appears the RT_STRING resource type requests a segment of 16 strings not an individual string. */ cchGot = LoadStringW(hInstance, (UINT)dwStringId, wszBuf, cchBuf); if (cchGot < cchBuf - 1) { // Good, got the whole string. break; } // Uh oh, LoadStringW filled the buffer entirely which could mean the // string was truncated. Try again with a larger buffer to be sure it // wasn't. LocalFree(wszBuf); cchBuf += 256; } return(wszBuf); } /* Following functions are required around the messy CONN_PROP structure to support v1/v0 etc. This is really bad. All the functions assume that version 1.0 format is passed in. */ EAPTLS_CONN_PROPERTIES_V1_EXTRA UNALIGNED * ConnPropGetExtraPointer (EAPTLS_CONN_PROPERTIES * pConnProp) { return (EAPTLS_CONN_PROPERTIES_V1_EXTRA UNALIGNED *) ( pConnProp->awszServerName + wcslen(pConnProp->awszServerName) + 1); } DWORD ConnPropGetNumHashes(EAPTLS_CONN_PROPERTIES * pConnProp ) { EAPTLS_CONN_PROPERTIES_V1_EXTRA UNALIGNED * pExtra = ConnPropGetExtraPointer(pConnProp); return pExtra->dwNumHashes; } void ConnPropSetNumHashes(EAPTLS_CONN_PROPERTIES * pConnProp, DWORD dwNumHashes ) { EAPTLS_CONN_PROPERTIES_V1_EXTRA UNALIGNED * pExtra = ConnPropGetExtraPointer(pConnProp); pExtra->dwNumHashes = dwNumHashes; return; } DWORD ConnPropGetV1Struct ( EAPTLS_CONN_PROPERTIES * pConnProp, EAPTLS_CONN_PROPERTIES_V1 ** ppConnPropv1 ) { DWORD dwRetCode = NO_ERROR; EAPTLS_CONN_PROPERTIES_V1 * pConnPropv1 = NULL; EAPTLS_CONN_PROPERTIES_V1_EXTRA UNALIGNED * pExtra = ConnPropGetExtraPointer(pConnProp); // //This function assumes that the struct that comes in is at //version 1. Which means at least sizeof(EAPTLS_CONN_PROPERTIES) + //EAPTLS_CONN_PROPERTIES_V1_EXTRA in size. // // //First get the amount of memory required to be allocated // pConnPropv1 = LocalAlloc ( LPTR, sizeof( EAPTLS_CONN_PROPERTIES_V1 ) + //sizeof the basic struct pExtra->dwNumHashes * sizeof( EAPTLS_HASH ) + //num hashes wcslen( pConnProp->awszServerName ) * sizeof(WCHAR) + sizeof(WCHAR)//sizeof the string ); if ( NULL == pConnPropv1 ) { dwRetCode = GetLastError(); goto LDone; } // //Convert the structure // if ( pConnProp->dwVersion <= 1 ) pConnPropv1->dwVersion = 1; else pConnPropv1->dwVersion = 2; pConnPropv1->dwSize = sizeof( EAPTLS_CONN_PROPERTIES_V1 ) + pExtra->dwNumHashes * sizeof( EAPTLS_HASH ) + wcslen( pConnProp->awszServerName ) * sizeof(WCHAR) + sizeof(WCHAR); pConnPropv1->fFlags = pConnProp->fFlags; pConnPropv1->dwNumHashes = pExtra->dwNumHashes; if ( pExtra->dwNumHashes ) { CopyMemory( pConnPropv1->bData, &(pConnProp->Hash), sizeof(EAPTLS_HASH) ); if ( pExtra->dwNumHashes >1 ) { CopyMemory ( pConnPropv1->bData + sizeof(EAPTLS_HASH), pExtra->bData, (pExtra->dwNumHashes -1 ) * sizeof(EAPTLS_HASH) ); } } //Copy the server name wcscpy( (WCHAR *)( pConnPropv1->bData + (pExtra->dwNumHashes * sizeof(EAPTLS_HASH) ) ), pConnProp->awszServerName ); *ppConnPropv1 = pConnPropv1; pConnPropv1 = NULL; LDone: LocalFree(pConnPropv1); return dwRetCode; } DWORD ConnPropGetV0Struct ( EAPTLS_CONN_PROPERTIES_V1 * pConnPropv1, EAPTLS_CONN_PROPERTIES ** ppConnProp ) { DWORD dwRetCode = NO_ERROR; EAPTLS_CONN_PROPERTIES * pConnProp = NULL; DWORD dwSize = 0; EAPTLS_CONN_PROPERTIES_V1_EXTRA UNALIGNED * pExtrav1 = NULL; // //First calulate the amount of memory to allocate // dwSize = sizeof(EAPTLS_CONN_PROPERTIES) + (pConnPropv1->dwNumHashes?( pConnPropv1->dwNumHashes - 1 ) * sizeof(EAPTLS_HASH):0) + ( wcslen( (LPWSTR) (pConnPropv1->bData + (pConnPropv1->dwNumHashes * sizeof(EAPTLS_HASH)) ) ) * sizeof(WCHAR) ) + sizeof(WCHAR); pConnProp = LocalAlloc ( LPTR, dwSize ); if ( NULL == pConnProp ) { dwRetCode = GetLastError(); goto LDone; } if ( pConnPropv1->dwVersion <= 1 ) pConnProp->dwVersion = 1; else pConnProp->dwVersion = 2; pConnProp->dwSize = dwSize; pConnProp->fFlags = pConnPropv1->fFlags; if ( pConnPropv1->dwNumHashes > 0 ) { CopyMemory( &(pConnProp->Hash), pConnPropv1->bData, sizeof(EAPTLS_HASH)); } if ( pConnPropv1->bData ) { wcscpy ( pConnProp->awszServerName, (LPWSTR )(pConnPropv1->bData + sizeof( EAPTLS_HASH ) * pConnPropv1->dwNumHashes) ); } pExtrav1 = (EAPTLS_CONN_PROPERTIES_V1_EXTRA UNALIGNED *)(pConnProp->awszServerName + wcslen( pConnProp->awszServerName) + 1); pExtrav1->dwNumHashes = pConnPropv1->dwNumHashes; if ( pExtrav1->dwNumHashes > 1 ) { CopyMemory( pExtrav1->bData, pConnPropv1->bData + sizeof(EAPTLS_HASH), ( pConnPropv1->dwNumHashes - 1 ) * sizeof(EAPTLS_HASH) ); } *ppConnProp = pConnProp; pConnProp = NULL; LDone: LocalFree(pConnProp); return dwRetCode; } void ShowCertDetails ( HWND hWnd, HCERTSTORE hStore, PCCERT_CONTEXT pCertContext) { CRYPTUI_VIEWCERTIFICATE_STRUCT vcs; BOOL fPropertiesChanged = FALSE; ZeroMemory (&vcs, sizeof (vcs)); vcs.dwSize = sizeof (vcs); vcs.hwndParent = hWnd; vcs.pCertContext = pCertContext; vcs.cStores = 1; vcs.rghStores = &hStore; vcs.dwFlags |= (CRYPTUI_DISABLE_EDITPROPERTIES|CRYPTUI_DISABLE_ADDTOSTORE); CryptUIDlgViewCertificate (&vcs, &fPropertiesChanged); return; } #if 0 // Location of policy parameters #define cwszEAPOLPolicyParams L"Software\\Policies\\Microsoft\\Windows\\Network Connections\\8021X" #define cszCARootHash "8021XCARootHash" #define SIZE_OF_CA_CONV_STR 3 #define SIZE_OF_HASH 20 // // ReadGPCARootHashes // // Description: // // Function to read parameters created by policy downloads // Currently, 8021XCARootHash will be downloaded to the HKLM // // Arguments: // pdwSizeOfRootHashBlob - Size of hash blob in bytes. Each root CA hash // will be of SIZE_OF_HASH bytes // ppbRootHashBlob - Pointer to hash blob. Caller should free it using // LocalFree // // Return values: // ERROR_SUCCESS - success // !ERROR_SUCCESS - error // DWORD ReadGPCARootHashes( DWORD *pdwSizeOfRootHashBlob, PBYTE *ppbRootHashBlob ) { HKEY hKey = NULL; DWORD dwType = 0; DWORD dwSize = 0; CHAR *pszCARootHash = NULL; DWORD i = 0; CHAR cszCharConv[SIZE_OF_CA_CONV_STR]; BYTE *pbRootHashBlob = NULL; DWORD dwSizeOfHashBlob = 0; LONG lError = ERROR_SUCCESS; lError = RegOpenKeyEx( HKEY_LOCAL_MACHINE, cwszEAPOLPolicyParams, 0, KEY_READ, &hKey ); if (lError != ERROR_SUCCESS) { EapTlsTrace("ReadCARootHashes: RegOpenKeyEx failed with error %ld", lError); goto LDone; } lError = RegQueryValueExA( hKey, cszCARootHash, 0, &dwType, NULL, &dwSize ); if (lError == ERROR_SUCCESS) { // Each SHA1 hash will be 2*SIZE_OF_HASH chars // Each BYTE in the hash will be represented by 2 CHARs, // 1 for each nibble // The hashblob should contain an integral number of hashes if ((dwSize-1*sizeof(CHAR))%(2*SIZE_OF_HASH*sizeof(CHAR))) { EapTlsTrace("ReadCARootHashes: Invalid hash length (%ld)", dwSize); goto LDone; } pszCARootHash = (CHAR *)LocalAlloc(LPTR, dwSize); if (pszCARootHash == NULL) { lError = GetLastError(); EapTlsTrace("ReadCARootHashes: LocalAlloc failed for pwszCARootHash"); goto LDone; } lError = RegQueryValueExA( hKey, cszCARootHash, 0, &dwType, (BYTE *)pszCARootHash, &dwSize ); if (lError != ERROR_SUCCESS) { EapTlsTrace("ReadCARootHashes: RegQueryValueEx 2 failed with error (%ld)", lError); goto LDone; } dwSizeOfHashBlob = (dwSize-1*sizeof(CHAR))/(2*sizeof(CHAR)); if ((pbRootHashBlob = LocalAlloc ( LPTR, dwSizeOfHashBlob*sizeof(BYTE))) == NULL) { lError = GetLastError(); EapTlsTrace("ReadCARootHashes: LocalAlloc failed for pbRootHashBlob"); goto LDone; } for (i=0; iUserProperties ); return NO_ERROR; } DWORD PeapGetFirstEntryConnProp ( PPEAP_CONN_PROP pConnProp, PEAP_ENTRY_CONN_PROPERTIES UNALIGNED ** ppEntryProp ) { DWORD dwRetCode = NO_ERROR; PEAP_ENTRY_CONN_PROPERTIES UNALIGNED *pFirstEntryConnProp = NULL; LPWSTR lpwszServerName; RTASSERT ( NULL != pConnProp ); RTASSERT ( NULL != ppEntryProp ); lpwszServerName = (LPWSTR )(pConnProp->EapTlsConnProp.bData + sizeof( EAPTLS_HASH ) * pConnProp->EapTlsConnProp.dwNumHashes); //Get the first entry in connprop pFirstEntryConnProp = ( PEAP_ENTRY_CONN_PROPERTIES UNALIGNED *) ( pConnProp->EapTlsConnProp.bData + pConnProp->EapTlsConnProp.dwNumHashes * sizeof(EAPTLS_HASH) + (lpwszServerName? wcslen(lpwszServerName) * sizeof(WCHAR):0) + sizeof(WCHAR) ); if (NULL == pFirstEntryConnProp ) { dwRetCode = ERROR_NOT_FOUND; goto LDone; } *ppEntryProp = pFirstEntryConnProp; LDone: return dwRetCode; } DWORD PeapReadConnectionData( IN BOOL fWireless, IN BYTE* pConnectionDataIn, IN DWORD dwSizeOfConnectionDataIn, OUT PPEAP_CONN_PROP* ppConnProp ) { DWORD dwRetCode = NO_ERROR; PPEAP_CONN_PROP pConnProp = NULL; PEAP_ENTRY_CONN_PROPERTIES UNALIGNED * pEntryProp = NULL; EapTlsTrace("PeapReadConnectionData"); RTASSERT(NULL != ppConnProp); if ( dwSizeOfConnectionDataIn < sizeof(PEAP_CONN_PROP) ) { pConnProp = LocalAlloc(LPTR, sizeof(PEAP_CONN_PROP) + sizeof(PEAP_ENTRY_CONN_PROPERTIES)+ sizeof(WCHAR)); if (NULL == pConnProp) { dwRetCode = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwRetCode); goto LDone; } //This is a new structure pConnProp->dwVersion = 1; pConnProp->dwSize = sizeof(PEAP_CONN_PROP) + sizeof(PEAP_ENTRY_CONN_PROPERTIES); pConnProp->EapTlsConnProp.dwVersion = 1; pConnProp->EapTlsConnProp.dwSize = sizeof(EAPTLS_CONN_PROPERTIES_V1); pConnProp->EapTlsConnProp.fFlags |= EAPTLS_CONN_FLAG_REGISTRY; pConnProp->EapTlsConnProp.fFlags |= EAPTLS_CONN_FLAG_SIMPLE_CERT_SEL; pConnProp->dwNumPeapTypes = 1; //pEntryProp = (PPEAP_ENTRY_CONN_PROPERTIES)(((PBYTE)(pConnProp)) + sizeof(PEAP_CONN_PROP) + sizeof(WCHAR)); pEntryProp = ( PEAP_ENTRY_CONN_PROPERTIES UNALIGNED *) ( pConnProp->EapTlsConnProp.bData + pConnProp->EapTlsConnProp.dwNumHashes * sizeof(EAPTLS_HASH) + sizeof(WCHAR) ); // // Also setup the first peap entry conn prop and set it to // eapmschapv2 // if ( fWireless ) { pConnProp->EapTlsConnProp.fFlags |= EAPTLS_CONN_FLAG_NO_VALIDATE_NAME; } pEntryProp->dwVersion = 1; pEntryProp->dwSize = sizeof(PEAP_ENTRY_CONN_PROPERTIES); pEntryProp->dwEapTypeId = PPP_EAP_MSCHAPv2; } else { RTASSERT(NULL != pConnectionDataIn); // //Check to see if this is a version 0 structure //If it is a version 0 structure then we migrate it to version1 // pConnProp = LocalAlloc(LPTR, dwSizeOfConnectionDataIn); if (NULL == pConnProp) { dwRetCode = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwRetCode); goto LDone; } // If the user has mucked with the phonebook, we mustn't be affected. // The size must be correct. CopyMemory(pConnProp, pConnectionDataIn, dwSizeOfConnectionDataIn); pConnProp->dwSize = dwSizeOfConnectionDataIn; pConnProp->EapTlsConnProp.fFlags |= EAPTLS_CONN_FLAG_REGISTRY; } *ppConnProp = pConnProp; pConnProp = NULL; LDone: LocalFree(pConnProp); return dwRetCode; } DWORD PeapReDoUserData ( IN DWORD dwNewTypeId, OUT PPEAP_USER_PROP* ppNewUserProp ) { DWORD dwRetCode = NO_ERROR; PPEAP_USER_PROP pUserProp = NULL; EapTlsTrace("PeapReDoUserData"); pUserProp = LocalAlloc(LPTR, sizeof(PEAP_USER_PROP)); if (NULL == pUserProp) { dwRetCode = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwRetCode); goto LDone; } pUserProp->dwVersion = 1; pUserProp->dwSize = sizeof(PEAP_USER_PROP); // // Setup the default user prop... // pUserProp->UserProperties.dwVersion = 1; pUserProp->UserProperties.dwSize = sizeof(PEAP_ENTRY_USER_PROPERTIES); pUserProp->UserProperties.dwEapTypeId = dwNewTypeId; *ppNewUserProp = pUserProp; LDone: return dwRetCode; } DWORD PeapReadUserData( IN BYTE* pUserDataIn, IN DWORD dwSizeOfUserDataIn, OUT PPEAP_USER_PROP* ppUserProp ) { DWORD dwErr = NO_ERROR; PPEAP_USER_PROP pUserProp; EapTlsTrace("PeapReadUserData"); if (dwSizeOfUserDataIn < sizeof(PEAP_USER_PROP)) { pUserProp = LocalAlloc(LPTR, sizeof(PEAP_USER_PROP)); if (NULL == pUserProp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } pUserProp->dwVersion = 1; pUserProp->dwSize = sizeof(PEAP_USER_PROP); // // Setup the default user prop... // pUserProp->UserProperties.dwVersion = 1; pUserProp->UserProperties.dwSize = sizeof(PEAP_ENTRY_USER_PROPERTIES); pUserProp->UserProperties.dwEapTypeId = PPP_EAP_MSCHAPv2; } else { RTASSERT(NULL != pUserDataIn); pUserProp = LocalAlloc(LPTR, dwSizeOfUserDataIn); if (NULL == pUserProp) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } CopyMemory(pUserProp, pUserDataIn, dwSizeOfUserDataIn); pUserProp->dwVersion = 1; pUserProp->dwSize = dwSizeOfUserDataIn; } *ppUserProp = pUserProp; pUserProp = NULL; LDone: LocalFree(pUserProp); return dwErr; } // // Add node at the head // DWORD PeapEapInfoAddListNode (PPEAP_EAP_INFO * ppEapInfo) { PPEAP_EAP_INFO pEapInfo = NULL; DWORD dwRetCode = NO_ERROR; pEapInfo = (PPEAP_EAP_INFO)LocalAlloc(LPTR, sizeof(PEAP_EAP_INFO)); if ( NULL == pEapInfo ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } if ( NULL == *ppEapInfo ) { *ppEapInfo = pEapInfo; } else { pEapInfo->pNext = *ppEapInfo; *ppEapInfo = pEapInfo; } LDone: return dwRetCode; } DWORD PeapEapInfoCopyListNode ( DWORD dwTypeId, PPEAP_EAP_INFO pEapInfoList, PPEAP_EAP_INFO * ppEapInfo ) { DWORD dwRetCode = ERROR_NOT_FOUND; PPEAP_EAP_INFO pEapInfoListInternal = pEapInfoList; while ( pEapInfoListInternal ) { if ( pEapInfoListInternal->dwTypeId == dwTypeId ) { *ppEapInfo = LocalAlloc( LPTR, sizeof(PEAP_EAP_INFO) ); if ( NULL == *ppEapInfo ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } CopyMemory ( *ppEapInfo, pEapInfoListInternal, sizeof(PEAP_EAP_INFO) ); dwRetCode = NO_ERROR; goto LDone; } pEapInfoListInternal = pEapInfoListInternal->pNext; } LDone: return dwRetCode; } DWORD PeapEapInfoFindListNode ( DWORD dwTypeId, PPEAP_EAP_INFO pEapInfoList, PPEAP_EAP_INFO * ppEapInfo ) { DWORD dwRetCode = ERROR_NOT_FOUND; PPEAP_EAP_INFO pEapInfoListInternal = pEapInfoList; while ( pEapInfoListInternal ) { if ( pEapInfoListInternal->dwTypeId == dwTypeId ) { *ppEapInfo = pEapInfoListInternal; dwRetCode = NO_ERROR; goto LDone; } pEapInfoListInternal = pEapInfoListInternal->pNext; } LDone: return dwRetCode; } VOID PeapEapInfoFreeNodeData ( PPEAP_EAP_INFO pEapInfo ) { LocalFree ( pEapInfo->lpwszFriendlyName ); LocalFree ( pEapInfo->lpwszConfigUIPath ); LocalFree ( pEapInfo->lpwszIdentityUIPath ); LocalFree ( pEapInfo->lpwszConfigClsId ); LocalFree ( pEapInfo->pbNewClientConfig ); LocalFree ( pEapInfo->lpwszInteractiveUIPath ); LocalFree ( pEapInfo->lpwszPath); if ( pEapInfo->hEAPModule ) { FreeLibrary(pEapInfo->hEAPModule); } } VOID PeapEapInfoRemoveHeadNode(PPEAP_EAP_INFO * ppEapInfo) { PPEAP_EAP_INFO pEapInfo = *ppEapInfo; if ( pEapInfo ) { *ppEapInfo = pEapInfo->pNext; PeapEapInfoFreeNodeData(pEapInfo); LocalFree ( pEapInfo ); } } VOID PeapEapInfoFreeList ( PPEAP_EAP_INFO pEapInfo ) { PPEAP_EAP_INFO pNext; while ( pEapInfo ) { pNext = pEapInfo->pNext; PeapEapInfoFreeNodeData(pEapInfo); LocalFree ( pEapInfo ); pEapInfo = pNext; } } DWORD PeapEapInfoReadSZ (HKEY hkeyPeapType, LPWSTR pwszValue, LPWSTR * ppValueData ) { DWORD dwRetCode = NO_ERROR; DWORD dwType = 0; DWORD cbValueDataSize =0; PBYTE pbValue = NULL; dwRetCode = RegQueryValueEx( hkeyPeapType, pwszValue, NULL, &dwType, pbValue, &cbValueDataSize ); if ( dwRetCode != NO_ERROR ) { goto LDone; } pbValue = (PBYTE)LocalAlloc ( LPTR, cbValueDataSize ); if ( NULL == pbValue ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } dwRetCode = RegQueryValueEx( hkeyPeapType, pwszValue, NULL, &dwType, pbValue, &cbValueDataSize ); if ( dwRetCode != NO_ERROR ) { goto LDone; } *ppValueData = (LPWSTR)pbValue; pbValue = NULL; LDone: LocalFree ( pbValue ); return dwRetCode; } DWORD PeapEapInfoExpandSZ (HKEY hkeyPeapType, LPWSTR pwszValue, LPWSTR * ppValueData ) { DWORD dwRetCode = NO_ERROR; DWORD dwType = 0; DWORD cbValueDataSize =0; PBYTE pbValue = NULL; PBYTE pbExpandedValue = NULL; dwRetCode = RegQueryValueEx( hkeyPeapType, pwszValue, NULL, &dwType, pbValue, &cbValueDataSize ); if ( dwRetCode != NO_ERROR ) { goto LDone; } pbValue = (PBYTE)LocalAlloc ( LPTR, cbValueDataSize ); if ( NULL == pbValue ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } dwRetCode = RegQueryValueEx( hkeyPeapType, pwszValue, NULL, &dwType, pbValue, &cbValueDataSize ); if ( dwRetCode != NO_ERROR ) { goto LDone; } //now Expand the exvironment string cbValueDataSize = ExpandEnvironmentStrings( (LPWSTR)pbValue, NULL, 0 ); pbExpandedValue = (PBYTE)LocalAlloc ( LPTR, cbValueDataSize * sizeof(WCHAR) ); if ( NULL == pbExpandedValue ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } cbValueDataSize = ExpandEnvironmentStrings( (LPWSTR)pbValue, (LPWSTR)pbExpandedValue, sizeof(WCHAR) * cbValueDataSize ); if ( cbValueDataSize == 0 ) { dwRetCode = GetLastError(); goto LDone; } *ppValueData = (LPWSTR)pbExpandedValue; pbExpandedValue = NULL; LDone: LocalFree ( pbValue ); LocalFree ( pbExpandedValue ); return dwRetCode; } BOOL IsPeapCrippled(HKEY hKeyLM) { BOOL fRetCode = FALSE; DWORD dwRetCode = NO_ERROR; HKEY hCripple = 0; DWORD dwValue = 0; DWORD dwType = 0; DWORD cbValueDataSize = sizeof(DWORD); dwRetCode = RegOpenKeyEx( hKeyLM, PEAP_KEY_PEAP, 0, KEY_READ, &hCripple ); if (NO_ERROR != dwRetCode) { goto LDone; } dwRetCode = RegQueryValueEx( hCripple, PEAP_CRIPPLE_VALUE, NULL, &dwType, (PBYTE)&dwValue, &cbValueDataSize ); if ( dwRetCode != NO_ERROR ) { goto LDone; } if ( dwValue != 0 ) { fRetCode = TRUE; } LDone: if ( hCripple ) RegCloseKey ( hCripple ); return fRetCode; } // // Get a list of all EAP types configured for PEAP. // DWORD PeapEapInfoGetList ( LPWSTR lpwszMachineName, PPEAP_EAP_INFO * ppEapInfo) { DWORD dwRetCode = NO_ERROR; HKEY hKeyLM =0; HKEY hKeyPeap = 0; HKEY hkeyPeapType = 0; DWORD dwIndex; DWORD cb; WCHAR wszPeapType[200]; DWORD dwEapTypeId = 0; FARPROC pRasEapGetInfo; dwRetCode = RegConnectRegistry ( lpwszMachineName, HKEY_LOCAL_MACHINE, &hKeyLM ); if ( NO_ERROR != dwRetCode ) { goto LDone; } dwRetCode = RegOpenKeyEx( hKeyLM, PEAP_KEY_EAP, 0, KEY_READ, &hKeyPeap ); if (NO_ERROR != dwRetCode) { goto LDone; } for (dwIndex = 0; TRUE; ++dwIndex) { cb = sizeof(wszPeapType) / sizeof(WCHAR); dwRetCode = RegEnumKeyEx( hKeyPeap, dwIndex, wszPeapType, &cb, NULL, NULL, NULL, NULL ); if (dwRetCode != NO_ERROR) { // Includes "out of items", the normal loop termination. // dwRetCode = NO_ERROR; break; } dwRetCode = RegOpenKeyEx( hKeyPeap, wszPeapType, 0, KEY_READ, &hkeyPeapType ); if (dwRetCode != NO_ERROR) { dwRetCode = NO_ERROR; continue; } dwEapTypeId = _wtol(wszPeapType); if ( dwEapTypeId == PPP_EAP_PEAP ) { dwRetCode = NO_ERROR; continue; } { // // Check to see if we support this in peap // By default we do. DWORD dwRolesSupported = 0; DWORD cbValueSize = sizeof(dwRolesSupported); DWORD dwType = 0; dwRetCode = RegQueryValueEx( hkeyPeapType, PEAP_REGVAL_ROLESSUPPORTED, NULL, &dwType, (PBYTE)&dwRolesSupported, &cbValueSize ); if ( dwRetCode == NO_ERROR ) { // // We dont allow this method in PEAP. // if ( RAS_EAP_ROLE_EXCLUDE_IN_PEAP & dwRolesSupported ) { continue; } } } // // Read the required information and setup the node here // dwRetCode = PeapEapInfoAddListNode (ppEapInfo); if ( NO_ERROR != dwRetCode ) { goto LDone; } // // Setup the list node - if any of these entries are not // found skip the entry // (*ppEapInfo)->dwTypeId = dwEapTypeId; dwRetCode = PeapEapInfoReadSZ ( hkeyPeapType, PEAP_REGVAL_FRIENDLYNAME, &((*ppEapInfo)->lpwszFriendlyName ) ); if ( NO_ERROR != dwRetCode ) { if ( ERROR_FILE_NOT_FOUND == dwRetCode ) { PeapEapInfoRemoveHeadNode(ppEapInfo); dwRetCode = NO_ERROR; continue; } goto LDone; } dwRetCode = PeapEapInfoExpandSZ ( hkeyPeapType, PEAP_REGVAL_CONFIGDLL, &((*ppEapInfo)->lpwszConfigUIPath ) ); if ( NO_ERROR != dwRetCode ) { if ( ERROR_FILE_NOT_FOUND == dwRetCode ) { // it is fine to have no config stuff any more. // We show the default identity dwRetCode = NO_ERROR; } else { goto LDone; } } dwRetCode = PeapEapInfoExpandSZ ( hkeyPeapType, PEAP_REGVAL_IDENTITYDLL, &((*ppEapInfo)->lpwszIdentityUIPath ) ); if ( NO_ERROR != dwRetCode ) { if ( ERROR_FILE_NOT_FOUND == dwRetCode ) { // // It is fine if we dont have any identity UI. Peap // will provide a default identity UI // dwRetCode = NO_ERROR; } else { goto LDone; } } dwRetCode = PeapEapInfoExpandSZ ( hkeyPeapType, PEAP_REGVAL_INTERACTIVEUIDLL, &((*ppEapInfo)->lpwszInteractiveUIPath ) ); if ( NO_ERROR != dwRetCode ) { if ( ERROR_FILE_NOT_FOUND == dwRetCode ) { //It is fine if we dont have interactive UI // dwRetCode = NO_ERROR; } else { goto LDone; } } dwRetCode = PeapEapInfoReadSZ ( hkeyPeapType, PEAP_REGVAL_CONFIGCLSID, &((*ppEapInfo)->lpwszConfigClsId ) ); if ( NO_ERROR != dwRetCode ) { if ( ERROR_FILE_NOT_FOUND == dwRetCode ) { // // Missing config clsid is also fine dwRetCode = NO_ERROR; } else { goto LDone; } } dwRetCode = PeapEapInfoExpandSZ ( hkeyPeapType, PEAP_REGVAL_PATH, &((*ppEapInfo)->lpwszPath ) ); if ( NO_ERROR != dwRetCode ) { // // This is not acceptable. So this is a problem. // if ( ERROR_FILE_NOT_FOUND == dwRetCode ) { PeapEapInfoRemoveHeadNode(ppEapInfo); dwRetCode = NO_ERROR; continue; } goto LDone; } // // Now get the EAP INFO from the DLL. // (*ppEapInfo)->hEAPModule = LoadLibrary( ( (*ppEapInfo)->lpwszPath ) ); if ( NULL == (*ppEapInfo)->hEAPModule ) { dwRetCode = GetLastError(); goto LDone; } pRasEapGetInfo = GetProcAddress( (*ppEapInfo)->hEAPModule , "RasEapGetInfo" ); if ( pRasEapGetInfo == (FARPROC)NULL ) { dwRetCode = GetLastError(); goto LDone; } (*ppEapInfo)->RasEapGetCredentials = (DWORD (*) ( DWORD,VOID *, VOID **)) GetProcAddress((*ppEapInfo)->hEAPModule, "RasEapGetCredentials"); (*ppEapInfo)->PppEapInfo.dwSizeInBytes = sizeof( PPP_EAP_INFO ); dwRetCode = (DWORD) (*pRasEapGetInfo)( dwEapTypeId, &((*ppEapInfo)->PppEapInfo) ); if ( dwRetCode != NO_ERROR ) { goto LDone; } // // Call initialize function here // if ( (*ppEapInfo)->PppEapInfo.RasEapInitialize ) { (*ppEapInfo)->PppEapInfo.RasEapInitialize(TRUE); } RegCloseKey(hkeyPeapType); hkeyPeapType = 0; } LDone: if ( hkeyPeapType ) RegCloseKey(hkeyPeapType); if ( hKeyPeap ) RegCloseKey(hKeyPeap); if ( hKeyLM ) RegCloseKey(hKeyLM); if ( NO_ERROR != dwRetCode ) { PeapEapInfoFreeList( *ppEapInfo ); } return dwRetCode; } DWORD PeapEapInfoSetConnData ( PPEAP_EAP_INFO pEapInfo, PPEAP_CONN_PROP pPeapConnProp ) { DWORD dwRetCode = NO_ERROR; PEAP_ENTRY_CONN_PROPERTIES UNALIGNED *pEntryProp = NULL; PPEAP_EAP_INFO pEapInfoLocal; DWORD dwCount; RTASSERT(NULL != pPeapConnProp); RTASSERT(NULL != pEapInfo); if ( !pPeapConnProp->dwNumPeapTypes ) { goto LDone; } // // Right now there is only one EAP Type in the list // So it should not be a problem with this stuff now pEntryProp = ( PEAP_ENTRY_CONN_PROPERTIES*) ( pPeapConnProp->EapTlsConnProp.bData + pPeapConnProp->EapTlsConnProp.dwNumHashes * sizeof(EAPTLS_HASH) + sizeof(WCHAR) ); pEapInfoLocal = pEapInfo; while( pEapInfoLocal ) { if ( pEapInfoLocal->dwTypeId == pEntryProp->dwEapTypeId ) { if ( pEntryProp->dwSize > sizeof(PEAP_ENTRY_CONN_PROPERTIES)) { pEapInfoLocal->pbClientConfigOrig = pEntryProp->bData; pEapInfoLocal->dwClientConfigOrigSize = pEntryProp->dwSize - sizeof(PEAP_ENTRY_CONN_PROPERTIES) + 1; } else { pEapInfoLocal->pbClientConfigOrig = NULL; pEapInfoLocal->dwClientConfigOrigSize = 0; } break; } pEapInfoLocal = pEapInfoLocal->pNext; } #if 0 for ( dwCount = 0; dwCount < pPeapConnProp->dwNumPeapTypes; dwCount ++ ) { pEntryProp = (PEAP_ENTRY_CONN_PROPERTIES UNALIGNED * )(((BYTE UNALIGNED *)&(pPeapConnProp->EapTlsConnProp)) + pPeapConnProp->EapTlsConnProp.dwSize + sizeof(PEAP_ENTRY_CONN_PROPERTIES) * dwCount); pEapInfoLocal = pEapInfo; while( pEapInfoLocal ) { if ( pEapInfoLocal->dwTypeId == pEntryProp->dwEapTypeId ) { if ( pEntryProp->dwSize > sizeof(PEAP_ENTRY_CONN_PROPERTIES)) { pEapInfoLocal->pbClientConfigOrig = pEntryProp->bData; pEapInfoLocal->dwClientConfigOrigSize = pEntryProp->dwSize - sizeof(PEAP_ENTRY_CONN_PROPERTIES) + 1; } else { pEapInfoLocal->pbClientConfigOrig = NULL; pEapInfoLocal->dwClientConfigOrigSize = 0; } break; } pEapInfoLocal = pEapInfoLocal->pNext; } } #endif LDone: return dwRetCode; } DWORD PeapEapInfoInvokeIdentityUI ( HWND hWndParent, PPEAP_EAP_INFO pEapInfo, const WCHAR * pwszPhoneBook, const WCHAR * pwszEntry, PBYTE pbUserDataIn, // Got when using Winlogon DWORD cbUserDataIn, // Got when using Winlogon WCHAR** ppwszIdentityOut, DWORD fFlags) { DWORD dwRetCode = NO_ERROR; PBYTE pbUserDataNew = NULL; DWORD dwSizeOfUserDataNew = 0; RASEAPGETIDENTITY pIdenFunc = NULL; RASEAPFREE pFreeFunc = NULL; RTASSERT ( NULL != pEapInfo ); RTASSERT ( NULL != pEapInfo->lpwszIdentityUIPath ); pIdenFunc = (RASEAPGETIDENTITY) GetProcAddress(pEapInfo->hEAPModule, "RasEapGetIdentity"); if ( pIdenFunc == NULL) { dwRetCode = GetLastError(); goto LDone; } pFreeFunc = (RASEAPFREE) GetProcAddress(pEapInfo->hEAPModule, "RasEapFreeMemory"); if ( pFreeFunc == NULL ) { dwRetCode = GetLastError(); goto LDone; } dwRetCode = pIdenFunc ( pEapInfo->dwTypeId, hWndParent, fFlags, pwszPhoneBook, pwszEntry, pEapInfo->pbClientConfigOrig, pEapInfo->dwClientConfigOrigSize, ( fFlags & RAS_EAP_FLAG_LOGON ? pbUserDataIn: pEapInfo->pbUserConfigOrig ), ( fFlags & RAS_EAP_FLAG_LOGON ? cbUserDataIn: pEapInfo->dwUserConfigOrigSize ), &pbUserDataNew, &dwSizeOfUserDataNew, ppwszIdentityOut ); if ( NO_ERROR != dwRetCode ) { goto LDone; } if ( pbUserDataNew && dwSizeOfUserDataNew ) { // // we have new user data // pEapInfo->pbUserConfigNew = (PBYTE)LocalAlloc (LPTR, dwSizeOfUserDataNew ); if ( NULL == pEapInfo->pbUserConfigNew ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } CopyMemory ( pEapInfo->pbUserConfigNew, pbUserDataNew, dwSizeOfUserDataNew ); pEapInfo->dwNewUserConfigSize = dwSizeOfUserDataNew; } LDone: pFreeFunc( pbUserDataNew ); return dwRetCode; } DWORD PeapEapInfoInvokeClientConfigUI ( HWND hWndParent, PPEAP_EAP_INFO pEapInfo, DWORD fFlags) { DWORD dwRetCode = NO_ERROR; RASEAPINVOKECONFIGUI pInvokeConfigUI; RASEAPFREE pFreeConfigUIData; PBYTE pConnDataOut = NULL; DWORD dwConnDataOut = 0; RTASSERT ( NULL != pEapInfo ); RTASSERT ( NULL != pEapInfo->lpwszConfigUIPath ); if ( !(pInvokeConfigUI = (RASEAPINVOKECONFIGUI )GetProcAddress( pEapInfo->hEAPModule, "RasEapInvokeConfigUI" )) || !(pFreeConfigUIData = (RASEAPFREE) GetProcAddress( pEapInfo->hEAPModule, "RasEapFreeMemory" )) ) { dwRetCode = GetLastError(); goto LDone; } dwRetCode = pInvokeConfigUI ( pEapInfo->dwTypeId, hWndParent, fFlags, (pEapInfo->pbNewClientConfig? pEapInfo->pbNewClientConfig: pEapInfo->pbClientConfigOrig ), (pEapInfo->pbNewClientConfig? pEapInfo->dwNewClientConfigSize: pEapInfo->dwClientConfigOrigSize ), &pConnDataOut, &dwConnDataOut ); if ( NO_ERROR != dwRetCode ) { goto LDone; } if ( pConnDataOut && dwConnDataOut ) { if ( pEapInfo->pbNewClientConfig ) { LocalFree(pEapInfo->pbNewClientConfig ); pEapInfo->pbNewClientConfig = NULL; pEapInfo->dwNewClientConfigSize = 0; } pEapInfo->pbNewClientConfig = (PBYTE)LocalAlloc ( LPTR, dwConnDataOut ); if ( NULL == pEapInfo->pbNewClientConfig ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } CopyMemory( pEapInfo->pbNewClientConfig, pConnDataOut, dwConnDataOut ); pEapInfo->dwNewClientConfigSize = dwConnDataOut; } LDone: if ( pConnDataOut ) pFreeConfigUIData(pConnDataOut); return dwRetCode; } DWORD OpenPeapRegistryKey( IN WCHAR* pwszMachineName, IN REGSAM samDesired, OUT HKEY* phKeyPeap ) { HKEY hKeyLocalMachine = NULL; BOOL fHKeyLocalMachineOpened = FALSE; BOOL fHKeyPeapOpened = FALSE; LONG lRet; DWORD dwErr = NO_ERROR; RTASSERT(NULL != phKeyPeap); lRet = RegConnectRegistry(pwszMachineName, HKEY_LOCAL_MACHINE, &hKeyLocalMachine); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegConnectRegistry(%ws) failed and returned %d", pwszMachineName ? pwszMachineName : L"NULL", dwErr); goto LDone; } fHKeyLocalMachineOpened = TRUE; lRet = RegOpenKeyEx(hKeyLocalMachine, PEAP_KEY_25, 0, samDesired, phKeyPeap); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegOpenKeyEx(%ws) failed and returned %d", PEAP_KEY_25, dwErr); goto LDone; } fHKeyPeapOpened = TRUE; LDone: if ( fHKeyPeapOpened && (ERROR_SUCCESS != dwErr)) { RegCloseKey(*phKeyPeap); } if (fHKeyLocalMachineOpened) { RegCloseKey(hKeyLocalMachine); } return(dwErr); } DWORD PeapServerConfigDataIO( IN BOOL fRead, IN WCHAR* pwszMachineName, IN OUT BYTE** ppData, IN DWORD dwNumBytes ) { HKEY hKeyPeap; PEAP_USER_PROP* pUserProp; BOOL fHKeyPeapOpened = FALSE; BYTE* pData = NULL; DWORD dwSize = 0; LONG lRet; DWORD dwType; DWORD dwErr = NO_ERROR; RTASSERT(NULL != ppData); dwErr = OpenPeapRegistryKey(pwszMachineName, fRead ? KEY_READ : KEY_WRITE, &hKeyPeap); if (ERROR_SUCCESS != dwErr) { goto LDone; } fHKeyPeapOpened = TRUE; if (fRead) { lRet = RegQueryValueEx(hKeyPeap, PEAP_VAL_SERVER_CONFIG_DATA, NULL, &dwType, NULL, &dwSize); if ( (ERROR_SUCCESS != lRet) || (REG_BINARY != dwType) || (sizeof(PEAP_USER_PROP) != dwSize)) { pData = LocalAlloc(LPTR, sizeof(PEAP_USER_PROP)); if (NULL == pData) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } pUserProp = (PEAP_USER_PROP*)pData; pUserProp->dwVersion = 0; } else { pData = LocalAlloc(LPTR, dwSize); if (NULL == pData) { dwErr = GetLastError(); EapTlsTrace("LocalAlloc failed and returned %d", dwErr); goto LDone; } lRet = RegQueryValueEx(hKeyPeap, PEAP_VAL_SERVER_CONFIG_DATA, NULL, &dwType, pData, &dwSize); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegQueryValueEx(%ws) failed and returned %d", EAPTLS_VAL_SERVER_CONFIG_DATA, dwErr); goto LDone; } } pUserProp = (PEAP_USER_PROP*)pData; pUserProp->dwSize = sizeof(PEAP_USER_PROP); *ppData = pData; pData = NULL; } else { lRet = RegSetValueEx(hKeyPeap, PEAP_VAL_SERVER_CONFIG_DATA, 0, REG_BINARY, *ppData, dwNumBytes); if (ERROR_SUCCESS != lRet) { dwErr = lRet; EapTlsTrace("RegSetValueEx(%ws) failed and returned %d", PEAP_VAL_SERVER_CONFIG_DATA, dwErr); goto LDone; } } LDone: if (fHKeyPeapOpened) { RegCloseKey(hKeyPeap); } LocalFree(pData); return(dwErr); } DWORD GetIdentityFromUserName ( LPWSTR lpszUserName, LPWSTR lpszDomain, LPWSTR * ppwszIdentity ) { DWORD dwRetCode = NO_ERROR; DWORD dwNumBytes; //domain+ user + '\' + null dwNumBytes = (wcslen(lpszUserName) + wcslen(lpszDomain) + 1 + 1) * sizeof(WCHAR); *ppwszIdentity = LocalAlloc ( LPTR, dwNumBytes); if ( NULL == *ppwszIdentity ) { dwRetCode = ERROR_OUTOFMEMORY; goto LDone; } if ( *lpszDomain ) { wcsncpy ( *ppwszIdentity, lpszDomain, DNLEN ); wcscat( *ppwszIdentity, L"\\"); } wcscat ( *ppwszIdentity, lpszUserName ); LDone: return dwRetCode; } // // Format identity as domain\user. this is ok because our identity inside has not been // tampered with // BOOL FFormatUserIdentity ( LPWSTR lpszUserNameRaw, LPWSTR * lppszUserNameFormatted ) { BOOL fRetVal = TRUE; LPTSTR s1 = NULL; LPTSTR s2 = NULL; RTASSERT(NULL != lpszUserNameRaw ); RTASSERT(NULL != lppszUserNameFormatted ); //Need to add 2 more chars. One for NULL and other for $ sign *lppszUserNameFormatted = (LPTSTR )LocalAlloc ( LPTR, (wcslen(lpszUserNameRaw ) + 2)* sizeof(WCHAR) ); if ( NULL == *lppszUserNameFormatted ) { return FALSE; } //find the first "@" and that is the identity of the machine. //the second "." is the domain. //check to see if there at least 2 dots. If not the raw string is //the output string s1 = wcschr ( lpszUserNameRaw, '@' ); if ( s1 ) { // // get the first . // s2 = wcschr ( s1, '.'); } if ( s1 && s2 ) { memcpy ( *lppszUserNameFormatted, s1+1, (s2-s1-1) * sizeof(WCHAR)) ; memcpy ( (*lppszUserNameFormatted) + (s2-s1-1), L"\\", sizeof(WCHAR)); memcpy ( (*lppszUserNameFormatted)+ (s2-s1), lpszUserNameRaw, (s1-lpszUserNameRaw) * sizeof(WCHAR) ); } else { wcscpy ( *lppszUserNameFormatted, lpszUserNameRaw ); } return fRetVal; } VOID GetMarshalledCredFromHash( PBYTE pbHash, DWORD cbHash, CHAR *pszMarshalledCred, DWORD cchCredSize) { CERT_CREDENTIAL_INFO CertCredInfo; CHAR *pszMarshalledCredLocal = NULL; CertCredInfo.cbSize = sizeof(CertCredInfo); memcpy (CertCredInfo.rgbHashOfCert, pbHash, cbHash ); if (CredMarshalCredentialA(CertCredential, (PVOID) &CertCredInfo, &pszMarshalledCredLocal )) { // // Got Marshalled Credential from the cert // Set it in the username field // ASSERT( NULL != pszMarshalledCredLocal ); (VOID) StringCchCopyA (pszMarshalledCred, cchCredSize, pszMarshalledCredLocal ); CredFree ( pszMarshalledCredLocal ); } else { EapTlsTrace("CredMarshalCredential Failed with Error:0x%x", GetLastError()); } } DWORD GetCredentialsFromUserProperties( EAPTLSCB *pEapTlsCb, VOID **ppCredentials) { DWORD dwRetCode = ERROR_SUCCESS; RASMAN_CREDENTIALS *pCreds = NULL; // // Note: Its important that this allocation is made from // the process heap. Ppp engine needs to change otherwise. // pCreds = LocalAlloc(LPTR, sizeof(RASMAN_CREDENTIALS)); if(NULL == pCreds) { dwRetCode = GetLastError(); goto done; } if( (NULL != pEapTlsCb->pSavedPin) && (NULL != pEapTlsCb->pSavedPin->pwszPin)) { UNICODE_STRING UnicodeString; // // Decode the saved pin // UnicodeString.Length = pEapTlsCb->pSavedPin->usLength; UnicodeString.MaximumLength = pEapTlsCb->pSavedPin->usMaximumLength; UnicodeString.Buffer = pEapTlsCb->pSavedPin->pwszPin; RtlRunDecodeUnicodeString(pEapTlsCb->pSavedPin->ucSeed, &UnicodeString); (VOID)StringCchCopyW(pCreds->wszPassword, PWLEN, pEapTlsCb->pSavedPin->pwszPin); ZeroMemory(pEapTlsCb->pSavedPin->pwszPin, wcslen(pEapTlsCb->pSavedPin->pwszPin) * sizeof(WCHAR)); LocalFree(pEapTlsCb->pSavedPin->pwszPin); LocalFree(pEapTlsCb->pSavedPin); pEapTlsCb->pSavedPin = NULL; } if(NULL != pEapTlsCb->pUserProp) { GetMarshalledCredFromHash( pEapTlsCb->pUserProp->Hash.pbHash, pEapTlsCb->pUserProp->Hash.cbHash, pCreds->szUserName, UNLEN); } pCreds->dwFlags = RASCRED_EAP; done: *ppCredentials = (VOID *) pCreds; return dwRetCode; }