SChannelDsc.psm1
|
#Region '.\prefix.ps1' -1 $script:dscResourceCommonModulePath = Join-Path -Path $PSScriptRoot -ChildPath 'Modules/DscResource.Common' Import-Module -Name $script:dscResourceCommonModulePath $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' #EndRegion '.\prefix.ps1' 5 #Region '.\Private\ConvertTo-TlsProtocolRegistryKeyName.ps1' -1 <# .SYNOPSIS Converts a protocol identifier to the SCHANNEL registry key name. .DESCRIPTION Maps protocol values from the `[System.Security.Authentication.SslProtocols]` enum to the actual SCHANNEL registry key names (e.g. 'TLS 1.2'). .PARAMETER Protocol The protocol value from the `[System.Security.Authentication.SslProtocols]` enum, e.g. `Tls12`, `Ssl3`, `Tls`. .OUTPUTS System.String .EXAMPLE ConvertTo-TlsProtocolRegistryKeyName -Protocol Tls12 Returns the string 'TLS 1.2'. #> function ConvertTo-TlsProtocolRegistryKeyName { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [System.Security.Authentication.SslProtocols] $Protocol ) $protocolRegistryKeyName = switch ($Protocol) { ([System.Security.Authentication.SslProtocols]::Ssl2) { 'SSL 2.0' } ([System.Security.Authentication.SslProtocols]::Ssl3) { 'SSL 3.0' } ([System.Security.Authentication.SslProtocols]::Tls) { 'TLS 1.0' } ([System.Security.Authentication.SslProtocols]::Tls11) { 'TLS 1.1' } ([System.Security.Authentication.SslProtocols]::Tls12) { 'TLS 1.2' } ([System.Security.Authentication.SslProtocols]::Tls13) { 'TLS 1.3' } default { $errorMessage = $script:localizedData.ConvertTo_TlsProtocolRegistryKeyName_UnknownProtocol -f $Protocol $exception = New-Exception -Message $errorMessage $errorRecord = New-ErrorRecord -Exception $exception -ErrorId 'CTTPRKN0001' -ErrorCategory ([System.Management.Automation.ErrorCategory]::InvalidArgument) -TargetObject $Protocol $PSCmdlet.ThrowTerminatingError($errorRecord) } } return $protocolRegistryKeyName } #EndRegion '.\Private\ConvertTo-TlsProtocolRegistryKeyName.ps1' 75 #Region '.\Private\Get-TlsProtocolRegistryPath.ps1' -1 <# .SYNOPSIS Returns the SCHANNEL registry path for a given protocol and target. .DESCRIPTION Builds the registry path under HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols for the provided friendly protocol name and selects the `Server` or `Client` subkey depending on the `-Client` switch. .PARAMETER Protocol The protocol identifier, e.g. 'Tls12'. .PARAMETER Client When specified, return the path for the `Client` subkey, otherwise return the `Server` subkey path. .INPUTS None. .OUTPUTS System.String .EXAMPLE Get-TlsProtocolRegistryPath -Protocol Tls12 Returns the string: 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server'. .EXAMPLE Get-TlsProtocolRegistryPath -Protocol Tls13 -Client Returns the string: 'HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.3\Client'. #> function Get-TlsProtocolRegistryPath { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] $Protocol, [Parameter()] [System.Management.Automation.SwitchParameter] $Client ) $protocolKeyName = ConvertTo-TlsProtocolRegistryKeyName -Protocol $Protocol $target = Get-TlsProtocolTargetRegistryName -Client:$Client return ('HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\{0}\{1}' -f $protocolKeyName, $target) } #EndRegion '.\Private\Get-TlsProtocolRegistryPath.ps1' 58 #Region '.\Private\Get-TlsProtocolTargetRegistryName.ps1' -1 <# .SYNOPSIS Returns the SCHANNEL protocol target name for registry keys. .DESCRIPTION Returns either 'Server' or 'Client' depending on the provided `-Client` switch. This centralizes the logic used by public commands for choosing the registry subkey name. .PARAMETER Client When specified, return 'Client', otherwise return 'Server'. .OUTPUTS System.String .EXAMPLE Get-TlsProtocolTargetRegistryName Returns the string 'Server'. .EXAMPLE Get-TlsProtocolTargetRegistryName -Client Returns the string 'Client'. #> function Get-TlsProtocolTargetRegistryName { [CmdletBinding()] [OutputType([System.String])] param ( [Parameter()] [System.Management.Automation.SwitchParameter] $Client ) if ($Client.IsPresent) { return 'Client' } return 'Server' } #EndRegion '.\Private\Get-TlsProtocolTargetRegistryName.ps1' 44 #Region '.\Private\Set-TlsProtocolRegistryValue.ps1' -1 <# .SYNOPSIS Sets TLS/SSL protocol registry values for enabling or disabling protocols. .DESCRIPTION Internal helper function that writes SCHANNEL protocol registry values under HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols. This function creates the registry key if it does not exist and sets the Enabled DWORD value. Optionally sets the DisabledByDefault value. The function handles ShouldProcess confirmation using the caller's PSCmdlet object. .PARAMETER Protocol One or more protocol names to set registry values for. Accepts values from the `[System.Security.Authentication.SslProtocols]` enum such as `Ssl2`, `Ssl3`, `Tls`, `Tls11`, `Tls12`, `Tls13`. .PARAMETER Enable Enables the protocol by setting Enabled to 1 and DisabledByDefault to 0. .PARAMETER Disable Disables the protocol by setting Enabled to 0 and DisabledByDefault to 1. .PARAMETER Client When specified, operate on the protocol `Client` registry key instead of the default `Server` key. .PARAMETER SetDisabledByDefault When specified, also set the DisabledByDefault registry value. .PARAMETER Force When specified, bypasses confirmation prompts and suppresses ShouldProcess confirmations. .PARAMETER Cmdlet The PSCmdlet object from the calling command, used to perform ShouldProcess confirmation. .INPUTS None. .OUTPUTS None. .EXAMPLE Set-TlsProtocolRegistryValue -Protocol Tls12 -Enable -SetDisabledByDefault Enables TLS 1.2 for server-side connections by setting the Enabled registry value to 1 and DisabledByDefault to 0. .EXAMPLE Set-TlsProtocolRegistryValue -Protocol Tls12, Tls13 -Enable Enables TLS 1.2 and TLS 1.3 for server-side connections. .EXAMPLE Set-TlsProtocolRegistryValue -Protocol Ssl3 -Disable -Client Disables SSL 3.0 for client-side connections by setting the Enabled registry value to 0. #> function Set-TlsProtocolRegistryValue { [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium', DefaultParameterSetName = 'Enable')] [OutputType()] param ( [Parameter(Mandatory = $true)] [System.Security.Authentication.SslProtocols[]] $Protocol, [Parameter(Mandatory = $true, ParameterSetName = 'Enable')] [System.Management.Automation.SwitchParameter] $Enable, [Parameter(Mandatory = $true, ParameterSetName = 'Disable')] [System.Management.Automation.SwitchParameter] $Disable, [Parameter()] [System.Management.Automation.SwitchParameter] $Client, [Parameter()] [System.Management.Automation.SwitchParameter] $SetDisabledByDefault, [Parameter()] [System.Management.Automation.SwitchParameter] $Force ) # Need to do this check with Get-Variable instead of $Confirm due to strict mode. if ($Force.IsPresent -and -not (Get-Variable -Name 'Confirm' -ValueOnly -ErrorAction SilentlyContinue)) { $ConfirmPreference = 'None' } foreach ($currentProtocol in $Protocol) { $protocolKeyName = ConvertTo-TlsProtocolRegistryKeyName -Protocol $currentProtocol $target = Get-TlsProtocolTargetRegistryName -Client:$Client if ($Enable.IsPresent) { $enabledValue = 1 $disabledByDefaultValue = 0 $descriptionMessage = $script:localizedData.Set_TlsProtocolRegistryValue_Enable_ShouldProcessDescription -f $protocolKeyName, $target $confirmationMessage = $script:localizedData.Set_TlsProtocolRegistryValue_Enable_ShouldProcessConfirmation -f $protocolKeyName $captionMessage = $script:localizedData.Set_TlsProtocolRegistryValue_Enable_ShouldProcessCaption $errorMessage = $script:localizedData.Set_TlsProtocolRegistryValue_FailedToEnable $errorId = 'STPRV0001' } else { $enabledValue = 0 $disabledByDefaultValue = 1 $descriptionMessage = $script:localizedData.Set_TlsProtocolRegistryValue_Disable_ShouldProcessDescription -f $protocolKeyName, $target $confirmationMessage = $script:localizedData.Set_TlsProtocolRegistryValue_Disable_ShouldProcessConfirmation -f $protocolKeyName $captionMessage = $script:localizedData.Set_TlsProtocolRegistryValue_Disable_ShouldProcessCaption $errorMessage = $script:localizedData.Set_TlsProtocolRegistryValue_FailedToDisable $errorId = 'STPRV0002' } if ($PSCmdlet.ShouldProcess($descriptionMessage, $confirmationMessage, $captionMessage)) { $regPath = Get-TlsProtocolRegistryPath -Protocol $currentProtocol -Client:$Client try { $null = New-Item -Path $regPath -Force -ErrorAction 'Stop' $null = New-ItemProperty -Path $regPath -Name 'Enabled' -Value $enabledValue -PropertyType DWord -Force -ErrorAction 'Stop' if ($SetDisabledByDefault.IsPresent) { $null = New-ItemProperty -Path $regPath -Name 'DisabledByDefault' -Value $disabledByDefaultValue -PropertyType DWord -Force -ErrorAction 'Stop' } } catch { $errorMessage = $errorMessage -f $currentProtocol $exception = New-Exception -Message $errorMessage -ErrorRecord $_ $errorRecord = New-ErrorRecord -Exception $exception -ErrorId $errorId -ErrorCategory 'InvalidOperation' -TargetObject $currentProtocol $PSCmdlet.ThrowTerminatingError($errorRecord) } } } } #EndRegion '.\Private\Set-TlsProtocolRegistryValue.ps1' 151 #Region '.\Public\Assert-TlsProtocol.ps1' -1 <# .SYNOPSIS Asserts that the specified TLS/SSL protocols are enabled or disabled. .DESCRIPTION Calls Test-TlsProtocol for the specified protocol(s) and throws a terminating error if the assertion fails. By default, the command asserts that the protocol(s) are enabled for server-side connections. Use the `-Client` switch to assert the `Client` key instead of the default `Server` key. Use the `-Disabled` switch to assert that the protocol(s) are disabled instead of enabled. .PARAMETER Protocol One or more protocol names to assert. Accepts values from the `[System.Security.Authentication.SslProtocols]` enum such as `Ssl2`, `Ssl3`, `Tls`, `Tls11`, `Tls12`, `Tls13`. .PARAMETER Client When specified, assert the protocol in the `Client` registry key instead of the default `Server` key. .PARAMETER Disabled When specified, asserts that the protocol(s) are disabled. By default the command asserts that the protocol(s) are enabled. .INPUTS None. .OUTPUTS None. .EXAMPLE Assert-TlsProtocol -Protocol Tls12 Asserts that TLS 1.2 is enabled for server-side connections. Throws a terminating error if TLS 1.2 is not enabled. .EXAMPLE Assert-TlsProtocol -Protocol Tls12 -Client Asserts that TLS 1.2 is enabled for client-side connections. .EXAMPLE Assert-TlsProtocol -Protocol Tls12 -Disabled Asserts that TLS 1.2 is disabled for server-side connections. Throws a terminating error if TLS 1.2 is still enabled. .EXAMPLE Assert-TlsProtocol -Protocol Ssl3, Tls -Disabled Asserts that both SSL 3.0 and TLS 1.0 are disabled for server-side connections. #> function Assert-TlsProtocol { [CmdletBinding()] [OutputType()] param ( [Parameter(Mandatory = $true)] [System.Security.Authentication.SslProtocols[]] $Protocol, [Parameter()] [System.Management.Automation.SwitchParameter] $Client, [Parameter()] [System.Management.Automation.SwitchParameter] $Disabled ) $result = Test-TlsProtocol -Protocol $Protocol -Client:$Client -Disabled:$Disabled if (-not $result) { if ($Disabled) { $message = ($script:localizedData.Assert_TlsProtocol_NotDisabled -f ($Protocol -join ', ')) } else { $message = ($script:localizedData.Assert_TlsProtocol_NotEnabled -f ($Protocol -join ', ')) } $exception = New-Exception -Message $message $errorRecord = New-ErrorRecord -Exception $exception -ErrorId 'ATP0001' -ErrorCategory 'InvalidOperation' -TargetObject $Protocol $PSCmdlet.ThrowTerminatingError($errorRecord) } } #EndRegion '.\Public\Assert-TlsProtocol.ps1' 92 #Region '.\Public\Disable-TlsProtocol.ps1' -1 <# .SYNOPSIS Disables specified TLS/SSL protocols by writing SCHANNEL registry values. .DESCRIPTION Disables SCHANNEL protocol keys under HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols for the server-side `Server` key by default. Use the `-Client` switch to operate on the `Client` key instead. The command will create the target key if it does not exist and set the `Enabled` DWORD to `0`. Optionally, when `-SetDisabledByDefault` is specified the command will also write `DisabledByDefault = 1` (opt-in only). .PARAMETER Protocol One or more protocol names to disable. Accepts values from the `[System.Security.Authentication.SslProtocols]` enum such as `Ssl2`, `Ssl3`, `Tls`, `Tls11`, `Tls12`, `Tls13`. .PARAMETER Client When specified, operate on the protocol `Client` registry key instead of the default `Server` key. .PARAMETER SetDisabledByDefault When specified, also set the `DisabledByDefault` DWORD to 1. This is an opt-in behavior to avoid unintentionally changing additional registry values. .PARAMETER Force Suppresses confirmation prompts. .INPUTS None. .OUTPUTS None. .EXAMPLE Disable-TlsProtocol -Protocol Ssl3 Disables SSL 3.0 for server-side connections by setting the `Enabled` registry value to 0. .EXAMPLE Disable-TlsProtocol -Protocol Tls -Client Disables TLS 1.0 for client-side connections. .EXAMPLE Disable-TlsProtocol -Protocol Ssl2, Ssl3 -SetDisabledByDefault Disables SSL 2.0 and SSL 3.0 for server-side connections and also sets the `DisabledByDefault` registry value to 1. .EXAMPLE Disable-TlsProtocol -Protocol Tls -Force Disables TLS 1.0 for server-side connections without prompting for confirmation. #> function Disable-TlsProtocol { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '', Justification = 'Because ShouldProcess is used in the called function Set-TlsProtocolRegistryValue')] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] [OutputType()] param ( [Parameter(Mandatory = $true)] [System.Security.Authentication.SslProtocols[]] $Protocol, [Parameter()] [System.Management.Automation.SwitchParameter] $Client, [Parameter()] [System.Management.Automation.SwitchParameter] $SetDisabledByDefault, [Parameter()] [System.Management.Automation.SwitchParameter] $Force ) # ShouldProcess is handled in Set-TlsProtocolRegistryValue Set-TlsProtocolRegistryValue @PSBoundParameters -Disable } #EndRegion '.\Public\Disable-TlsProtocol.ps1' 88 #Region '.\Public\Enable-TlsProtocol.ps1' -1 <# .SYNOPSIS Enables specified TLS/SSL protocols by writing SCHANNEL registry values. .DESCRIPTION Enables SCHANNEL protocol keys under HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols for the server-side `Server` key by default. Use the `-Client` switch to operate on the `Client` key instead. The command will create the target key if it does not exist and set the `Enabled` DWORD to `1`. Optionally, when `-SetDisabledByDefault` is specified the command will also write `DisabledByDefault = 0` (opt-in only). .PARAMETER Protocol One or more protocol names to enable. Accepts values from the `[System.Security.Authentication.SslProtocols]` enum such as `Ssl2`, `Ssl3`, `Tls`, `Tls11`, `Tls12`, `Tls13`. .PARAMETER Client When specified, operate on the protocol `Client` registry key instead of the default `Server` key. .PARAMETER SetDisabledByDefault When specified, also set the `DisabledByDefault` DWORD to 0. This is an opt-in behavior to avoid unintentionally changing additional registry values. .PARAMETER Force Suppresses confirmation prompts. .INPUTS None. .OUTPUTS None. .EXAMPLE Enable-TlsProtocol -Protocol Tls12 Enables TLS 1.2 for server-side connections by setting the `Enabled` registry value to 1. .EXAMPLE Enable-TlsProtocol -Protocol Tls13 -Client Enables TLS 1.3 for client-side connections. .EXAMPLE Enable-TlsProtocol -Protocol Tls12, Tls13 -SetDisabledByDefault Enables TLS 1.2 and TLS 1.3 for server-side connections and also sets the `DisabledByDefault` registry value to 0. .EXAMPLE Enable-TlsProtocol -Protocol Tls12 -Force Enables TLS 1.2 for server-side connections without prompting for confirmation. #> function Enable-TlsProtocol { [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '', Justification = 'Because ShouldProcess is used in the called function Set-TlsProtocolRegistryValue')] [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] [OutputType()] param ( [Parameter(Mandatory = $true)] [System.Security.Authentication.SslProtocols[]] $Protocol, [Parameter()] [System.Management.Automation.SwitchParameter] $Client, [Parameter()] [System.Management.Automation.SwitchParameter] $SetDisabledByDefault, [Parameter()] [System.Management.Automation.SwitchParameter] $Force ) # ShouldProcess is handled in Set-TlsProtocolRegistryValue Set-TlsProtocolRegistryValue @PSBoundParameters -Enable } #EndRegion '.\Public\Enable-TlsProtocol.ps1' 88 #Region '.\Public\Get-TlsProtocol.ps1' -1 <# .SYNOPSIS Returns configured SCHANNEL protocol settings for Server or Client. .DESCRIPTION Reads the `Enabled` and `DisabledByDefault` values for one or more SCHANNEL protocol keys and returns a PSCustomObject with the results. By default, all supported protocols are queried if no specific protocol is specified. .PARAMETER Protocol One or more protocol names. Accepts values from the `[System.Security.Authentication.SslProtocols]` enum such as `Ssl2`, `Ssl3`, `Tls`, `Tls11`, `Tls12`, `Tls13`. If not specified, all supported protocols are returned. .PARAMETER Client When specified, reads the `Client` key. By default the `Server` key is used. .INPUTS None. .OUTPUTS `System.Management.Automation.PSCustomObject` Returns one or more objects with the following properties: Protocol, Target, Enabled, DisabledByDefault, and RegistryPath. .EXAMPLE Get-TlsProtocol Returns the SCHANNEL protocol settings for all supported protocols for server-side connections. .EXAMPLE Get-TlsProtocol -Protocol Tls12 Returns the SCHANNEL protocol settings for TLS 1.2 for server-side connections. .EXAMPLE Get-TlsProtocol -Protocol Tls12, Tls13 -Client Returns the SCHANNEL protocol settings for TLS 1.2 and TLS 1.3 for client-side connections. .EXAMPLE Get-TlsProtocol | Format-Table -AutoSize Returns all protocol settings and displays them in a formatted table. #> function Get-TlsProtocol { [CmdletBinding()] [OutputType([System.Management.Automation.PSCustomObject])] param ( [Parameter()] [System.Security.Authentication.SslProtocols[]] $Protocol, [Parameter()] [System.Management.Automation.SwitchParameter] $Client ) if (-not $PSBoundParameters.ContainsKey('Protocol')) { $Protocol = [System.Collections.ArrayList] @( [System.Security.Authentication.SslProtocols]::Ssl2, [System.Security.Authentication.SslProtocols]::Ssl3, [System.Security.Authentication.SslProtocols]::Tls, [System.Security.Authentication.SslProtocols]::Tls11, [System.Security.Authentication.SslProtocols]::Tls12, [System.Security.Authentication.SslProtocols]::Tls13 ) if ([System.Enum]::GetNames([System.Security.Authentication.SslProtocols]) -notcontains 'Tls13') { $Protocol.Remove([System.Security.Authentication.SslProtocols]::Tls13) } } foreach ($currentProtocol in $Protocol) { $regPath = Get-TlsProtocolRegistryPath -Protocol $currentProtocol -Client:$Client $protocolEnabled = Get-RegistryPropertyValue -Path $regPath -Name 'Enabled' -ErrorAction SilentlyContinue $protocolDisabled = Get-RegistryPropertyValue -Path $regPath -Name 'DisabledByDefault' -ErrorAction SilentlyContinue $protocolEnabled = if ($null -ne $protocolEnabled) { [System.UInt32] $protocolEnabled } else { $null } $protocolDisabled = if ($null -ne $protocolDisabled) { [System.UInt32] $protocolDisabled } else { $null } [PSCustomObject] @{ Protocol = $currentProtocol Target = Get-TlsProtocolTargetRegistryName -Client:$Client Enabled = $protocolEnabled DisabledByDefault = $protocolDisabled RegistryPath = $regPath } } } #EndRegion '.\Public\Get-TlsProtocol.ps1' 118 #Region '.\Public\Test-TlsNegotiation.ps1' -1 <# .SYNOPSIS Tests which TLS/SSL protocols can be negotiated with a target host/port. .DESCRIPTION Test-TlsNegotiation attempts to establish a TCP connection to the specified HostName and Port, then performs a TLS/SSL handshake using each protocol provided in `-Protocol`. It uses System.Net.Security.SslStream and ignores certificate validation errors on purpose (the goal is to test protocol support, not certificate trust). For each attempted protocol, the function returns an object indicating whether the handshake succeeded, and if so, which protocol and cipher suite were negotiated. .PARAMETER HostName The DNS name or IP address of the target host. Default is 'localhost'. .PARAMETER Port The TCP port to connect to. Default is 443. .PARAMETER Protocol One or more protocol names to attempt. Accepts values from the `[System.Security.Authentication.SslProtocols]` enum such as `Ssl2`, `Ssl3`, `Tls`, `Tls11`, `Tls12`, `Tls13`. If not specified, all supported protocols are attempted. .PARAMETER TimeoutSeconds Connection timeout in seconds for the TCP connect attempt. Default is 5. .INPUTS None. .OUTPUTS `System.Management.Automation.PSCustomObject` Each output object contains: HostName, Port, AttemptedProtocol, Success, NegotiatedProtocol, NegotiatedCipherSuite, Error, and InnerError. .EXAMPLE Test-TlsNegotiation -HostName localhost Attempts each protocol against localhost using default port 443 and returns the results. .EXAMPLE Test-TlsNegotiation -HostName localhost -Port 1433 Attempts each protocol against localhost:1433 and returns the results. .EXAMPLE Test-TlsNegotiation -HostName localhost -Port 1433 | Format-Table -AutoSize Attempts each protocol against localhost:1433 and displays results in a formatted table. .EXAMPLE Test-TlsNegotiation -HostName sql01.contoso.com -Port 1433 -Verbose Tests protocol negotiation against sql01.contoso.com:1433 and prints each attempt via -Verbose. .EXAMPLE Test-TlsNegotiation -HostName webserver.contoso.com -Port 443 -Protocol Tls12, Tls13 Tests only TLS 1.2 and TLS 1.3 negotiation against a web server on port 443. .NOTES Certificate validation is intentionally bypassed to focus solely on protocol support. TLS 1.3 availability depends on OS and .NET runtime. #> function Test-TlsNegotiation { [CmdletBinding()] [OutputType([System.Management.Automation.PSCustomObject])] param ( [Parameter(Position = 0)] [ValidateNotNullOrEmpty()] [System.String] $HostName = 'localhost', [Parameter(Position = 1)] [ValidateRange(1, 65535)] [System.UInt16] $Port = 443, [Parameter()] [System.Security.Authentication.SslProtocols[]] $Protocol, [Parameter()] [ValidateRange(1, 600)] [System.UInt32] $TimeoutSeconds = 5 ) if (-not $PSBoundParameters.ContainsKey('Protocol')) { $Protocol = @( [System.Security.Authentication.SslProtocols]::Ssl2, [System.Security.Authentication.SslProtocols]::Ssl3, [System.Security.Authentication.SslProtocols]::Tls, [System.Security.Authentication.SslProtocols]::Tls11, [System.Security.Authentication.SslProtocols]::Tls12, [System.Security.Authentication.SslProtocols]::Tls13 ) } # Equivalent to: (sender, certificate, chain, sslPolicyErrors) => true $certValidationCallback = [System.Net.Security.RemoteCertificateValidationCallback] { param ( [Parameter()] $sender, [Parameter()] $certificate, [Parameter()] $chain, [Parameter()] $sslPolicyErrors ) return $true } foreach ($currentProtocol in $Protocol) { Write-Verbose -Message ($script:localizedData.Test_TlsNegotiation_TryingProtocol -f $currentProtocol) $client = $null $sslStream = $null try { $client = [System.Net.Sockets.TcpClient]::new() # Timeout logic (TcpClient.Connect() has no built-in timeout) $iar = $client.BeginConnect($HostName, $Port, $null, $null) try { if (-not $iar.AsyncWaitHandle.WaitOne([System.TimeSpan]::FromSeconds($TimeoutSeconds), $false)) { $message = $script:localizedData.Test_TlsNegotiation_ConnectTimeout -f $TimeoutSeconds $exception = New-Exception -Message $message $errorRecord = New-ErrorRecord -Exception $exception -ErrorId 'TTN0002' -ErrorCategory 'OperationTimeout' -TargetObject $HostName $PSCmdlet.ThrowTerminatingError($errorRecord) } } finally { $iar.AsyncWaitHandle.Dispose() } $client.EndConnect($iar) $sslStream = [System.Net.Security.SslStream]::new( $client.GetStream(), $false, $certValidationCallback, $null ) # Equivalent to SslClientAuthenticationOptions { TargetHost = host; EnabledSslProtocols = protocol } $opts = [System.Net.Security.SslClientAuthenticationOptions]::new() $opts.TargetHost = $HostName $opts.EnabledSslProtocols = $currentProtocol $sslStream.AuthenticateAsClient($opts) [PSCustomObject] @{ HostName = $HostName Port = $Port AttemptedProtocol = $currentProtocol Success = $true NegotiatedProtocol = $sslStream.SslProtocol NegotiatedCipherSuite = $sslStream.NegotiatedCipherSuite Error = $null InnerError = $null } } catch { $innerExceptionMessage = if ($_.Exception.InnerException) { $_.Exception.InnerException.Message } else { $null } [PSCustomObject] @{ HostName = $HostName Port = $Port AttemptedProtocol = $currentProtocol Success = $false NegotiatedProtocol = $null NegotiatedCipherSuite = $null Error = $_.Exception.Message InnerError = $innerExceptionMessage } } finally { if ($sslStream) { $sslStream.Dispose() } if ($client) { $client.Close() $client.Dispose() } } } } #EndRegion '.\Public\Test-TlsNegotiation.ps1' 229 #Region '.\Public\Test-TlsProtocol.ps1' -1 <# .SYNOPSIS Tests if specified TLS/SSL protocols are enabled on the local machine. .DESCRIPTION Tests one or more SCHANNEL protocol keys under HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols to determine whether the protocol is enabled or disabled for server-side or client-side connections. Returns `$true` if all specified protocols match the expected state, or `$false` if any do not. .PARAMETER Protocol One or more protocol names to check. Accepts values from the `[System.Security.Authentication.SslProtocols]` enum such as `Ssl2`, `Ssl3`, `Tls`, `Tls11`, `Tls12`, `Tls13`. .PARAMETER Client When specified, checks the protocol `Client` registry key instead of the default `Server` key. .PARAMETER Disabled When specified, tests that the protocol(s) are disabled. By default the command tests that the protocol(s) are enabled. .INPUTS None. .OUTPUTS `System.Boolean` Returns `$true` if all specified protocols match the expected state, `$false` otherwise. .EXAMPLE Test-TlsProtocol -Protocol Tls12 Tests if TLS 1.2 is enabled for server-side connections. .EXAMPLE Test-TlsProtocol -Protocol Tls13 -Client Tests if TLS 1.3 is enabled for client-side connections. .EXAMPLE Test-TlsProtocol -Protocol Tls12 -Disabled Tests if TLS 1.2 is disabled for server-side connections. .EXAMPLE Test-TlsProtocol -Protocol Ssl2, Ssl3 -Disabled Tests if both SSL 2.0 and SSL 3.0 are disabled for server-side connections. Returns `$true` only if both protocols are disabled. .EXAMPLE Test-TlsProtocol -Protocol Tls12 -Client -Disabled Tests if TLS 1.2 is disabled for client-side connections. #> function Test-TlsProtocol { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter(Mandatory = $true)] [System.Security.Authentication.SslProtocols[]] $Protocol, [Parameter()] [System.Management.Automation.SwitchParameter] $Client, [Parameter()] [System.Management.Automation.SwitchParameter] $Disabled ) foreach ($currentProtocol in $Protocol) { $regPath = Get-TlsProtocolRegistryPath -Protocol $currentProtocol -Client:$Client $protocolEnabled = Get-RegistryPropertyValue -Path $regPath -Name 'Enabled' -ErrorAction SilentlyContinue $protocolDisabled = Get-RegistryPropertyValue -Path $regPath -Name 'DisabledByDefault' -ErrorAction SilentlyContinue $protocolEnabled = if ($null -ne $protocolEnabled) { [System.Int32] $protocolEnabled } else { $null } $protocolDisabled = if ($null -ne $protocolDisabled) { [System.Int32] $protocolDisabled } else { $null } if ($Disabled.IsPresent) { # Missing keys imply the protocol is enabled by default, so -Disabled should fail if ($null -eq $protocolEnabled -and $null -eq $protocolDisabled) { return $false } # Consider protocol disabled when Enabled != 1 or DisabledByDefault == 1 if (($null -ne $protocolEnabled -and $protocolEnabled -ne 1) -or ($null -ne $protocolDisabled -and $protocolDisabled -eq 1)) { continue } else { return $false } } else { if ($null -eq $protocolEnabled -and $null -eq $protocolDisabled) { continue } if ((($protocolEnabled -eq 1 -and ($protocolDisabled -eq 0 -or $null -eq $protocolDisabled)) -or ($null -eq $protocolEnabled -and $protocolDisabled -eq 0))) { continue } else { return $false } } } return $true } #EndRegion '.\Public\Test-TlsProtocol.ps1' 139 |