Search code examples
powershellsslcertificatex509certificate

How do I download the certificate from a web server that is self signed using PowerShell?


I've found several answer about how to download the certificate for a website in PowerShell using TcpClient.

function Get-RemoteCertificate {
       
    [CmdletBinding()]
    [OutputType([System.Security.Cryptography.X509Certificates.X509Certificate])]
    param (
      [Parameter(Mandatory, ValueFromPipeline)]
      [ValidateNotNull()]
      [Uri]$Uri
    )

    process {
        try {# connecting
            $TcpClient = [System.Net.Sockets.TcpClient]::new($Uri.Host, $Uri.Port)
    
            try {# getting SSL
                $SslStream = [System.Net.Security.SslStream]::new($TcpClient.GetStream())
                $SslStream.AuthenticateAsClient($Uri.Host)
                $SslStream.RemoteCertificate
            } finally {
                $SslStream.Dispose()
            }# end SSL
    
        } finally {
            $TcpClient.Dispose()
        }# end connect
    }
}

But as the TLS handshake will fail when the certificate isn't trusted, I can't download self signed certificates and I will get the error

Exception calling ".ctor" with "2" argument(s): "A connection attempt failed because the connected party did not 
properly respond after a period of time, or established connection failed because connected host has failed to 
respond

Is there a way to download self signed certificates without using OpenSSL?


Solution

  • This answer is using an old HttpWebRequest that is depreciated and will not work with powershell 7. Taken from this great answer:

    The HttpWebRequest API surface has not been fully ported to the newer versions of .NET/Core, as detailed in this Github issue:

    HttpWebRequest is API which is obsolete - see https://github.com/dotnet/platform-compat/blob/master/docs/DE0003.md.
    We ported only the most important parts of it to .NET Core. The recommended Networking API is HttpClient.

    Without using your sample, you can achieve this simple task based on this answer

    $ub = new-object System.UriBuilder -argumentlist 'https', '1.1.1.1', 443
    $uri = $ub.Uri
    
    # Disable the verification: 
    [Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}
    $req = [Net.HttpWebRequest]::Create($Uri.AbsoluteUri)
    try {
        $req.GetResponse() | Out-Null
        # Export the file, or return it if you want to keep a function
        $req.ServicePoint.Certificate.Export("Cert") | Set-Content -Path "C:\temp\test.crt"  -Encoding Byte
    } catch {
        Write-Host Exception while checking URL $url`: $_ -f Red
    }