-
-
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.ReceiveTimeout
or.SendTimeout
to manage timeouts during the TLS handshake. There is also$SslStream.ReadTimeout
and.WriteTimeout
which 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 anAsyncCallback
which 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.