Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

5315 lines
139 KiB

/*
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 <nt.h> // Required by windows.h
#include <ntrtl.h> // Required by windows.h
#include <nturtl.h> // Required by windows.h
#include <windows.h> // Win32 base API's
#include <rasauth.h> // Required by raseapif.h
#include <rtutils.h> // For RTASSERT
#include <rasman.h> // For EAPLOGONINFO
#include <wintrust.h>
#include <softpub.h>
#include <mscat.h>
#define SECURITY_WIN32
#include <security.h> // For GetUserNameExA, CredHandle
#include <schannel.h>
#include <sspi.h> // For CredHandle
#include <wincrypt.h> // Required by sclogon.h
#include <winscard.h> // For SCardListReadersA
#include <sclogon.h> // For ScHelperGetCertFromLogonInfo
#include <cryptui.h>
#include <stdlib.h>
#include <raserror.h>
#include <commctrl.h>
#include <eaptypeid.h>
#include <eaptls.h>
#include <wincred.h>
#define STRSAFE_NO_DEPRECATE
#include <strsafe.h>
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; i<dwSizeOfHashBlob; i++)
{
ZeroMemory(cszCharConv, SIZE_OF_CA_CONV_STR);
cszCharConv[0]=pszCARootHash[2*i];
cszCharConv[1]=pszCARootHash[2*i+1];
pbRootHashBlob[i] = (BYTE)strtol(cszCharConv, NULL, 16);
}
}
else
{
EapTlsTrace("ReadCARootHashes: 802.1X Policy Parameters RegQueryValueEx 1 failed with error (%ld)",
lError);
goto LDone;
}
LDone:
if (lError != ERROR_SUCCESS)
{
if (pbRootHashBlob != NULL)
{
LocalFree(pbRootHashBlob);
}
}
else
{
*ppbRootHashBlob = pbRootHashBlob;
*pdwSizeOfRootHashBlob = dwSizeOfHashBlob;
}
if (hKey != NULL)
{
RegCloseKey(hKey);
}
if (pszCARootHash != NULL)
{
LocalFree(pszCARootHash);
}
return lError;
}
#endif
/////////////////////// ALL PEAP related utils go here ///////////////////////////
DWORD
PeapGetFirstEntryUserProp ( PPEAP_USER_PROP pUserProp,
PEAP_ENTRY_USER_PROPERTIES UNALIGNED ** ppEntryProp
)
{
* ppEntryProp = &( pUserProp->UserProperties );
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;
}