|
|
//+---------------------------------------------------------------------------
//
// 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; }
|