-
-
Save jstangroome/5945820 to your computer and use it in GitHub Desktop.
| [CmdletBinding()] | |
| param ( | |
| [Parameter(Mandatory=$true)] | |
| [string] | |
| $ComputerName, | |
| [int] | |
| $Port = 443 | |
| ) | |
| $Certificate = $null | |
| $TcpClient = New-Object -TypeName System.Net.Sockets.TcpClient | |
| try { | |
| $TcpClient.Connect($ComputerName, $Port) | |
| $TcpStream = $TcpClient.GetStream() | |
| $Callback = { param($sender, $cert, $chain, $errors) return $true } | |
| $SslStream = New-Object -TypeName System.Net.Security.SslStream -ArgumentList @($TcpStream, $true, $Callback) | |
| try { | |
| $SslStream.AuthenticateAsClient('') | |
| $Certificate = $SslStream.RemoteCertificate | |
| } finally { | |
| $SslStream.Dispose() | |
| } | |
| } finally { | |
| $TcpClient.Dispose() | |
| } | |
| if ($Certificate) { | |
| if ($Certificate -isnot [System.Security.Cryptography.X509Certificates.X509Certificate2]) { | |
| $Certificate = New-Object -TypeName System.Security.Cryptography.X509Certificates.X509Certificate2 -ArgumentList $Certificate | |
| } | |
| Write-Output $Certificate | |
| } |
Just wanted to say this is awesome, thanks!
Thank you!. This is great!
Would it be possible to save the certificate to a file as well?
@richardhicks you can call .Export(...) on the returned certificate object, specify the desired certificate file format as the argument, then pass the output bytes to Set-Content, e.g.:
$cert=(Get-RemoteSSLCertificate.ps1 foo.com)
Set-Content file.cer -Encoding Byte -Value $cert.Export('Cert')
Untested.
Thanks. I'll give it a try. Also, confirmed that adding the hostname to $SslStream.AuthenticateAsClient('') (e.g., $SslStream.AuthenticateAsClient('foo.example.net') works for sites configured with SNI.
Thanks
I modified my copy of the script to write the certificate to file with:
$CertExportDirectory = 'C:\temp\'
$CertExportName = $ComputerName + '_Port' + $Port.ToString() + '.cer'
$FilePath = Join-Path $CertExportDirectory -Child $CertExportName
Export-Certificate -Cert $Certificate -FilePath $FilePath
With output like "C:\temp\example.com_Port443.cer"
I also run a validation check with:
Test-Certificate $Certificate
You may want to set some of the non-default Test-Certificate parameters depending on use case.
Any ideas how to adapt this for retrieval of the certificate used by a remote SQL server (i.e. port 1433)? The script hangs at $SslStream.AuthenticateAsClient('') when I try to use it this way.
@sahmedz11 As it is currently written, the script will use default .NET timeouts. You can augment the script to set
$TcpClient.ReceiveTimeoutor.SendTimeoutto manage timeouts during the TLS handshake. There is also$SslStream.ReadTimeoutand.WriteTimeoutwhich could be set, but I'm not sure if these apply during theAuthenticateAsClient()call.To implement a custom TCP connection handshake timeout, significant changes would be required to replace
$TcpClient.Connect(...)with$TcpClient.BeginConnect(...)instead and implement anAsyncCallbackwhich is possible in PowerShell but not something I have tried.The script also very explicitly does not perform any certificate validation, its purpose is to return the certificate for deeper inspection, valid or not. However you can modify the
$Callback = { ... }line to capture and report any validation errors, or perform additional custom validation.