windows-nt/Source/XPSP1/NT/ds/security/protocols/schannel/lsa/spreg.c
2020-09-26 16:20:57 +08:00

782 lines
21 KiB
C

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: spreg.c
//
// Contents: Schannel registry management routines.
//
// Classes:
//
// Functions:
//
// History: 11-24-97 jbanes Enabled TLS
//
//----------------------------------------------------------------------------
#include <sslp.h>
#include "spreg.h"
HKEY g_hkBase = NULL;
HANDLE g_hParamEvent = NULL;
HANDLE g_hWait = NULL;
HKEY g_hkFipsBase = NULL;
HANDLE g_hFipsParamEvent = NULL;
HANDLE g_hFipsWait = NULL;
BOOL g_fManualCredValidation = MANUAL_CRED_VALIDATION_SETTING;
BOOL g_PctClientDisabledByDefault = PCT_CLIENT_DISABLED_SETTING;
BOOL g_Ssl2ClientDisabledByDefault = SSL2_CLIENT_DISABLED_SETTING;
DWORD g_dwEventLogging = DEFAULT_EVENT_LOGGING_SETTING;
DWORD g_ProtEnabled = DEFAULT_ENABLED_PROTOCOLS_SETTING;
BOOL g_fFipsMode = FALSE;
BOOL g_fFranceLocale = FALSE;
typedef struct enamap
{
TCHAR *pKey;
DWORD Mask;
} enamap;
enamap g_ProtMap[] =
{
{SP_REG_KEY_UNIHELLO TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_UNI_CLIENT},
{SP_REG_KEY_UNIHELLO TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_UNI_SERVER},
{SP_REG_KEY_PCT1 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_PCT1_CLIENT},
{SP_REG_KEY_PCT1 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_PCT1_SERVER},
{SP_REG_KEY_SSL2 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_SSL2_CLIENT},
{SP_REG_KEY_SSL2 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_SSL2_SERVER},
{SP_REG_KEY_SSL3 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_SSL3_CLIENT},
{SP_REG_KEY_SSL3 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_SSL3_SERVER},
{SP_REG_KEY_TLS1 TEXT("\\") SP_REG_KEY_CLIENT, SP_PROT_TLS1_CLIENT},
{SP_REG_KEY_TLS1 TEXT("\\") SP_REG_KEY_SERVER, SP_PROT_TLS1_SERVER}
};
VOID
SslWatchParamKey(
PVOID pCtxt,
BOOLEAN fWaitStatus);
VOID
FipsWatchParamKey(
PVOID pCtxt,
BOOLEAN fWaitStatus);
BOOL
SslReadRegOptions(
BOOL fFirstTime);
BOOL SPLoadRegOptions(void)
{
g_hParamEvent = CreateEvent(NULL,
FALSE,
FALSE,
NULL);
SslWatchParamKey(g_hParamEvent, FALSE);
g_hFipsParamEvent = CreateEvent(NULL,
FALSE,
FALSE,
NULL);
FipsWatchParamKey(g_hFipsParamEvent, FALSE);
return TRUE;
}
void SPUnloadRegOptions(void)
{
if (NULL != g_hWait)
{
RtlDeregisterWait(g_hWait);
g_hWait = NULL;
}
if(NULL != g_hkBase)
{
RegCloseKey(g_hkBase);
}
if(NULL != g_hParamEvent)
{
CloseHandle(g_hParamEvent);
}
if (NULL != g_hFipsWait)
{
RtlDeregisterWait(g_hFipsWait);
g_hFipsWait = NULL;
}
if(NULL != g_hkFipsBase)
{
RegCloseKey(g_hkFipsBase);
}
if(NULL != g_hFipsParamEvent)
{
CloseHandle(g_hFipsParamEvent);
}
}
BOOL
ReadRegistrySetting(
HKEY hReadKey,
HKEY hWriteKey,
LPCTSTR pszValueName,
DWORD * pdwValue,
DWORD dwDefaultValue)
{
DWORD dwSize;
DWORD dwType;
DWORD dwOriginalValue = *pdwValue;
dwSize = sizeof(DWORD);
if(RegQueryValueEx(hReadKey,
pszValueName,
NULL,
&dwType,
(PUCHAR)pdwValue,
&dwSize) != STATUS_SUCCESS)
{
*pdwValue = dwDefaultValue;
if(hWriteKey)
{
RegSetValueEx(hWriteKey,
pszValueName,
0,
REG_DWORD,
(PUCHAR)pdwValue,
sizeof(DWORD));
}
}
return (dwOriginalValue != *pdwValue);
}
////////////////////////////////////////////////////////////////////
//
// Name: SslWatchParamKey
//
// Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
// debug level, then utilizes thread pool to wait on
// changes to this registry key. Enables dynamic debug
// level changes, as this function will also be callback
// if registry key modified.
//
// Arguments: pCtxt is actually a HANDLE to an event. This event
// will be triggered when key is modified.
//
// Notes: .
//
VOID
SslWatchParamKey(
PVOID pCtxt,
BOOLEAN fWaitStatus)
{
NTSTATUS Status;
LONG lRes = ERROR_SUCCESS;
BOOL fFirstTime = FALSE;
DWORD disp;
if(g_hkBase == NULL)
{
// First time we've been called.
Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
SP_REG_KEY_BASE,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&g_hkBase,
&disp);
if(Status)
{
DebugLog((DEB_WARN,"Failed to open SCHANNEL key: 0x%x\n", Status));
return;
}
fFirstTime = TRUE;
}
if(pCtxt != NULL)
{
if (NULL != g_hWait)
{
Status = RtlDeregisterWait(g_hWait);
if(!NT_SUCCESS(Status))
{
DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
goto Reregister;
}
}
lRes = RegNotifyChangeKeyValue(
g_hkBase,
TRUE,
REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
(HANDLE)pCtxt,
TRUE);
if (ERROR_SUCCESS != lRes)
{
DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
// we're tanked now. No further notifications, so get this one
}
}
SslReadRegOptions(fFirstTime);
#if DBG
InitDebugSupport(g_hkBase);
#endif
Reregister:
if(pCtxt != NULL)
{
Status = RtlRegisterWait(&g_hWait,
(HANDLE)pCtxt,
SslWatchParamKey,
(HANDLE)pCtxt,
INFINITE,
WT_EXECUTEINPERSISTENTIOTHREAD|
WT_EXECUTEONLYONCE);
}
}
////////////////////////////////////////////////////////////////////
//
// Name: FipsWatchParamKey
//
// Synopsis: Sets RegNotifyChangeKeyValue() on param key, initializes
// debug level, then utilizes thread pool to wait on
// changes to this registry key. Enables dynamic debug
// level changes, as this function will also be callback
// if registry key modified.
//
// Arguments: pCtxt is actually a HANDLE to an event. This event
// will be triggered when key is modified.
//
// Notes: .
//
VOID
FipsWatchParamKey(
PVOID pCtxt,
BOOLEAN fWaitStatus)
{
NTSTATUS Status;
LONG lRes = ERROR_SUCCESS;
DWORD disp;
if(g_hkFipsBase == NULL)
{
// First time we've been called.
Status = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
SP_REG_FIPS_BASE_KEY,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&g_hkFipsBase,
&disp);
if(Status)
{
DebugLog((DEB_WARN,"Failed to open FIPS key: 0x%x\n", Status));
return;
}
}
if(pCtxt != NULL)
{
if (NULL != g_hFipsWait)
{
Status = RtlDeregisterWait(g_hFipsWait);
if(!NT_SUCCESS(Status))
{
DebugLog((DEB_WARN, "Failed to Deregister wait on registry key: 0x%x\n", Status));
goto Reregister;
}
}
lRes = RegNotifyChangeKeyValue(
g_hkFipsBase,
TRUE,
REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
(HANDLE)pCtxt,
TRUE);
if (ERROR_SUCCESS != lRes)
{
DebugLog((DEB_ERROR,"Debug RegNotify setup failed: 0x%x\n", lRes));
// we're tanked now. No further notifications, so get this one
}
}
SslReadRegOptions(FALSE);
Reregister:
if(pCtxt != NULL)
{
Status = RtlRegisterWait(&g_hFipsWait,
(HANDLE)pCtxt,
FipsWatchParamKey,
(HANDLE)pCtxt,
INFINITE,
WT_EXECUTEINPERSISTENTIOTHREAD|
WT_EXECUTEONLYONCE);
}
}
BOOL
SslReadRegOptions(
BOOL fFirstTime)
{
DWORD err;
DWORD dwType;
DWORD fVal;
DWORD dwSize;
DWORD dwValue;
HKEY hKey;
HKEY hWriteKey;
DWORD disp;
HKEY hSubKey;
DWORD i;
HKEY hkProtocols = NULL;
HKEY hkCiphers = NULL;
HKEY hkHashes = NULL;
HKEY hkKeyExch = NULL;
BOOL fFipsMode = FALSE;
BOOL fSettingsChanged = FALSE;
DWORD dwOriginalValue;
DebugLog((DEB_TRACE,"Load configuration parameters from registry.\n"));
// "FipsAlgorithmPolicy"
ReadRegistrySetting(
g_hkFipsBase,
0,
SP_REG_FIPS_POLICY,
&dwValue,
0);
if(dwValue == 1)
{
fFipsMode = TRUE;
}
if(fFipsMode != g_fFipsMode)
{
g_fFipsMode = fFipsMode;
fSettingsChanged = TRUE;
}
//
// Read top-level configuration options.
//
// Open top-level key that has write access.
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SP_REG_KEY_BASE,
0,
KEY_READ | KEY_SET_VALUE,
&hWriteKey) != STATUS_SUCCESS)
{
hWriteKey = 0;
}
// "EventLogging"
if(ReadRegistrySetting(
g_hkBase,
hWriteKey,
SP_REG_VAL_EVENTLOG,
&g_dwEventLogging,
DEFAULT_EVENT_LOGGING_SETTING))
{
fSettingsChanged = TRUE;
}
// "ManualCredValidation"
if(ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_MANUAL_CRED_VALIDATION,
&g_fManualCredValidation,
MANUAL_CRED_VALIDATION_SETTING))
{
fSettingsChanged = TRUE;
}
// "ClientCacheTime"
if(ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_CLIENT_CACHE_TIME,
&SchannelCache.dwClientLifespan,
SP_CACHE_CLIENT_LIFESPAN))
{
fSettingsChanged = TRUE;
}
// "ServerCacheTime"
if(ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_SERVER_CACHE_TIME,
&SchannelCache.dwServerLifespan,
SP_CACHE_SERVER_LIFESPAN))
{
fSettingsChanged = TRUE;
}
// "MaximumCacheSize"
if(ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_MAXUMUM_CACHE_SIZE,
&SchannelCache.dwMaximumEntries,
SP_MAXIMUM_CACHE_ELEMENTS))
{
fSettingsChanged = TRUE;
}
if(fFirstTime)
{
SchannelCache.dwCacheSize = SchannelCache.dwMaximumEntries;
}
// "MultipleProcessClientCache"
if(ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_MULTI_PROC_CLIENT_CACHE,
&g_fMultipleProcessClientCache,
FALSE))
{
fSettingsChanged = TRUE;
}
if(hWriteKey)
{
RegCloseKey(hWriteKey);
hWriteKey = 0;
}
//
// Enable/Disable Protocols
//
if(fFipsMode)
{
// Disable everything except TLS.
g_ProtEnabled = SP_PROT_TLS1;
}
else
{
DWORD dwProtEnabled = DEFAULT_ENABLED_PROTOCOLS_SETTING;
err = RegCreateKeyEx( g_hkBase,
SP_REG_KEY_PROTOCOL,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hkProtocols,
&disp);
if(err == ERROR_SUCCESS)
{
for(i=0; i < (sizeof(g_ProtMap)/sizeof(enamap)); i++)
{
if(g_ProtMap[i].Mask & SP_PROT_PCT1)
{
if(g_fFranceLocale)
{
// Don't allow PCT to be enabled in France.
continue;
}
}
err = RegCreateKeyEx( hkProtocols,
g_ProtMap[i].pKey,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&disp);
if(!err)
{
dwSize = sizeof(DWORD);
err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
if(!err)
{
if(fVal)
{
dwProtEnabled |= g_ProtMap[i].Mask;
}
else
{
dwProtEnabled &= ~g_ProtMap[i].Mask;
}
}
if(g_ProtMap[i].Mask & SP_PROT_PCT1_CLIENT)
{
// "DisabledByDefault"
ReadRegistrySetting(
hKey,
0,
SP_REG_VAL_DISABLED_BY_DEFAULT,
&g_PctClientDisabledByDefault,
PCT_CLIENT_DISABLED_SETTING);
}
if(g_ProtMap[i].Mask & SP_PROT_SSL2_CLIENT)
{
// "DisabledByDefault"
ReadRegistrySetting(
hKey,
0,
SP_REG_VAL_DISABLED_BY_DEFAULT,
&g_Ssl2ClientDisabledByDefault,
SSL2_CLIENT_DISABLED_SETTING);
}
RegCloseKey(hKey);
}
}
RegCloseKey(hkProtocols);
}
if(g_ProtEnabled != dwProtEnabled)
{
g_ProtEnabled = dwProtEnabled;
fSettingsChanged = TRUE;
}
}
//
// Enable/Disable Ciphers
//
if(fFipsMode)
{
// Disable everything except 3DES.
for(i=0; i < g_cAvailableCiphers; i++)
{
if(g_AvailableCiphers[i].aiCipher != CALG_3DES)
{
g_AvailableCiphers[i].fProtocol = 0;
}
}
}
else
{
err = RegCreateKeyEx( g_hkBase,
SP_REG_KEY_CIPHERS,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hkCiphers,
&disp);
if(err == ERROR_SUCCESS)
{
for(i=0; i < g_cAvailableCiphers; i++)
{
dwOriginalValue = g_AvailableCiphers[i].fProtocol;
g_AvailableCiphers[i].fProtocol = g_AvailableCiphers[i].fDefault;
fVal = g_AvailableCiphers[i].fDefault;
err = RegCreateKeyExA( hkCiphers,
g_AvailableCiphers[i].szName,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&disp);
if(!err)
{
dwSize = sizeof(DWORD);
err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
if(err)
{
fVal = g_AvailableCiphers[i].fDefault;
}
RegCloseKey(hKey);
}
g_AvailableCiphers[i].fProtocol &= fVal;
if(g_AvailableCiphers[i].fProtocol != dwOriginalValue)
{
fSettingsChanged = TRUE;
}
}
RegCloseKey(hkCiphers);
}
}
//
// Enable/Disable Hashes
//
err = RegCreateKeyEx( g_hkBase,
SP_REG_KEY_HASHES,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hkHashes,
&disp);
if(err == ERROR_SUCCESS)
{
for(i = 0; i < g_cAvailableHashes; i++)
{
dwOriginalValue = g_AvailableHashes[i].fProtocol;
g_AvailableHashes[i].fProtocol = g_AvailableHashes[i].fDefault;
fVal = g_AvailableHashes[i].fDefault;
err = RegCreateKeyExA( hkHashes,
g_AvailableHashes[i].szName,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&disp);
if(!err)
{
dwSize = sizeof(DWORD);
err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
if(err)
{
fVal = g_AvailableHashes[i].fDefault;
}
RegCloseKey(hKey);
}
g_AvailableHashes[i].fProtocol &= fVal;
if(dwOriginalValue != g_AvailableHashes[i].fProtocol)
{
fSettingsChanged = TRUE;
}
}
RegCloseKey(hkHashes);
}
//
// Enable/Disable Key Exchange algs.
//
if(fFipsMode)
{
// Disable everything except RSA.
for(i=0; i < g_cAvailableExch; i++)
{
if(g_AvailableExch[i].aiExch != CALG_RSA_KEYX &&
g_AvailableExch[i].aiExch != CALG_RSA_SIGN)
{
g_AvailableExch[i].fProtocol = 0;
}
}
}
else
{
err = RegCreateKeyEx( g_hkBase,
SP_REG_KEY_KEYEXCH,
0,
TEXT(""),
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hkKeyExch,
&disp);
if(err == ERROR_SUCCESS)
{
for(i = 0; i < g_cAvailableExch; i++)
{
dwOriginalValue = g_AvailableExch[i].fProtocol;
g_AvailableExch[i].fProtocol = g_AvailableExch[i].fDefault;
fVal = g_AvailableExch[i].fDefault;
err = RegCreateKeyExA( hkKeyExch,
g_AvailableExch[i].szName,
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_READ,
NULL,
&hKey,
&disp);
if(!err)
{
dwSize = sizeof(DWORD);
err = RegQueryValueEx(hKey, SP_REG_VAL_ENABLED, NULL, &dwType, (PUCHAR)&fVal, &dwSize);
if(err)
{
fVal = g_AvailableExch[i].fDefault;
}
g_AvailableExch[i].fProtocol &= fVal;
RegCloseKey(hKey);
}
if(dwOriginalValue != g_AvailableExch[i].fProtocol)
{
fSettingsChanged = TRUE;
}
}
RegCloseKey(hkKeyExch);
}
}
//
// Purge the session cache.
//
if(g_fCacheInitialized && fSettingsChanged)
{
SPCachePurgeEntries(NULL,
0,
NULL,
SSL_PURGE_CLIENT_ALL_ENTRIES |
SSL_PURGE_SERVER_ALL_ENTRIES);
}
return TRUE;
}