Leaked source code of windows server 2003
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.
 
 
 
 
 
 

887 lines
25 KiB

//+---------------------------------------------------------------------------
//
// 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"
#include <mapper.h>
#include <sidfilter.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_fSendIssuerList = TRUE;
DWORD g_dwCertMappingMethods = DEFAULT_CERTMAP_SETTING;
BOOL g_fFipsMode = FALSE;
BOOL g_fFranceLocale = FALSE;
BOOL g_SslS4U2SelfInitialized = FALSE;
typedef struct enamap
{
TCHAR *pKey;
DWORD Mask;
} enamap;
enamap g_ProtMap[] =
{
{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;
UNREFERENCED_PARAMETER(fWaitStatus);
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;
UNREFERENCED_PARAMETER(fWaitStatus);
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;
HKEY hKey;
HKEY hWriteKey;
DWORD disp;
DWORD i;
HKEY hkProtocols = NULL;
HKEY hkCiphers = NULL;
HKEY hkHashes = NULL;
HKEY hkKeyExch = NULL;
DWORD dwSetting = 0;
BOOL fSettingsChanged = FALSE;
DWORD dwOriginalValue;
DebugLog((DEB_TRACE,"Load configuration parameters from registry.\n"));
// "FipsAlgorithmPolicy"
ReadRegistrySetting(
g_hkFipsBase,
0,
SP_REG_FIPS_POLICY,
&dwSetting,
0);
if((dwSetting == 1) != g_fFipsMode)
{
g_fFipsMode = (dwSetting == 1);
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"
ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_MANUAL_CRED_VALIDATION,
&dwSetting,
MANUAL_CRED_VALIDATION_SETTING);
if((dwSetting != 0) != g_fManualCredValidation)
{
g_fManualCredValidation = (dwSetting != 0);
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"
ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_MULTI_PROC_CLIENT_CACHE,
&dwSetting,
FALSE);
if((dwSetting != 0) != g_fMultipleProcessClientCache)
{
g_fMultipleProcessClientCache = (dwSetting != 0);
fSettingsChanged = TRUE;
}
// "SendTrustedIssuerList"
ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_SEND_ISSUER_LIST,
&dwSetting,
TRUE);
if((dwSetting != 0) != g_fSendIssuerList)
{
g_fSendIssuerList = (dwSetting != 0);
fSettingsChanged = TRUE;
}
// "CertificateMappingMethods"
if(ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_CERT_MAPPING_METHODS,
&g_dwCertMappingMethods,
DEFAULT_CERTMAP_SETTING))
{
fSettingsChanged = TRUE;
if((g_dwCertMappingMethods & SP_REG_CERTMAP_SUBJECT_FLAG) == 0)
{
DebugLog((DEB_TRACE, "Subject/Issuer certificate mapping disabled\n"));
}
if((g_dwCertMappingMethods & SP_REG_CERTMAP_ISSUER_FLAG) == 0)
{
DebugLog((DEB_TRACE, "Issuer certificate mapping disabled\n"));
}
if((g_dwCertMappingMethods & SP_REG_CERTMAP_UPN_FLAG) == 0)
{
DebugLog((DEB_TRACE, "UPN certificate mapping disabled\n"));
}
if((g_dwCertMappingMethods & SP_REG_CERTMAP_S4U2SELF_FLAG) == 0)
{
DebugLog((DEB_TRACE, "S4U2Self certificate mapping disabled\n"));
}
}
if(hWriteKey)
{
RegCloseKey(hWriteKey);
hWriteKey = 0;
}
// "IssuerCacheTime"
ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_ISSUER_CACHE_TIME,
&IssuerCache.dwLifespan,
ISSUER_CACHE_LIFESPAN);
// "IssuerCacheSize"
ReadRegistrySetting(
g_hkBase,
0,
SP_REG_VAL_ISSUER_CACHE_SIZE,
&IssuerCache.dwMaximumEntries,
ISSUER_CACHE_SIZE);
if(fFirstTime)
{
IssuerCache.dwCacheSize = IssuerCache.dwMaximumEntries;
}
#ifdef ROGUE_DC
if(g_hSslRogueKey == NULL)
{
if(RegOpenKeyExW(HKEY_LOCAL_MACHINE,
SP_REG_ROGUE_BASE_KEY,
0,
KEY_READ,
&g_hSslRogueKey) != STATUS_SUCCESS)
{
DebugLog((DEB_WARN,"Failed to open \"rogue\" ssl key\n" ));
g_hSslRogueKey = NULL;
}
}
#endif
//
// Enable/Disable Protocols
//
if(g_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,
&dwSetting,
PCT_CLIENT_DISABLED_SETTING);
g_PctClientDisabledByDefault = (dwSetting != 0);
}
if(g_ProtMap[i].Mask & SP_PROT_SSL2_CLIENT)
{
// "DisabledByDefault"
ReadRegistrySetting(
hKey,
0,
SP_REG_VAL_DISABLED_BY_DEFAULT,
&dwSetting,
SSL2_CLIENT_DISABLED_SETTING);
g_Ssl2ClientDisabledByDefault = (dwSetting != 0);
}
RegCloseKey(hKey);
}
}
RegCloseKey(hkProtocols);
}
if(g_ProtEnabled != dwProtEnabled)
{
g_ProtEnabled = dwProtEnabled;
fSettingsChanged = TRUE;
}
}
//
// Enable/Disable Ciphers
//
if(g_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(g_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;
}