Using System.Net.WebClient in PowerShell to access a HTTPS URL with SAN Certificate

23,384

My hunch is that this is less related to the PowerShell version (or underlying platform details in general) and more related to the certificate and the HTTPS handshake. It could be there have been improvements in recognizing alternate subject names embedded in a certificate, but an easy way to test it would be to add this line of PowerShell into your script:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }

This will cause all certificates to be accepted - regardless if they are trusted or not, expired, etc. This is a big hammer and it wouldn't be wise to use it in production setting, but it could be useful in helping to diagnose what it going on in your setup.

You can see more information on the ServerCertificateValidationCallback on the MSDN page including the parameters it passes into the delegate. You could in theory just whitelist the certificate you are using on that one server and return true for that one.

Share:
23,384
Robin
Author by

Robin

Updated on February 06, 2020

Comments

  • Robin
    Robin over 4 years

    Bit of an odd problem here. The script we're using is:

    $username = "itrpo"
    $url = "https://homepages.domain.com/cgi-bin/checkperms.cgi?user=$username"
    $homepagesUser = "REMOVED"
    $homepagesPass = "REMOVED"
    $webclient = New-Object System.Net.WebClient
    $webclient.Credentials = new-object System.Net.NetworkCredential($homepagesUser, $homepagesPass)
    $result = $webclient.DownloadString($url)
    

    When running this from my desktop (Windows 8, PowerShell v3 using .NET v4.0.30319) it works. When running this from a server (Windows Server 2008 R2, PowerShell v2 using .NET v2.0.50727) it does not. Ultimately it hangs and returns the error: Exception calling "DownloadString" with "1" argument(s): "The operation has timed out"

    Using NetMon I managed to determine that on the server it was failing to perform any TLS client key exchange.

    The SSL certificate for homepages.domain.com is actually a SAN certificate, with homepages being an alias for the actual server name (let's call it servera.domain.com). When I changed $url in the script to use the actual server name as so:

    $url = "https://servera.domain.com/cgi-bin/checkperms.cgi?user=$username"
    

    ... it worked, but this is not ideal (if the service is moved to another machine the script will break).

    It seems as though PowerShell v2 (.NET v2) is having problems with the SAN certificate? Further evidence to support this is that we use the above style script against another server with a standard SSL certificate it communicates fine.

    Could it be due to differences in the WebClient class being used? Here is the documentation for it under .NET v2: http://msdn.microsoft.com/en-us/library/system.net.webclient%28v=vs.80%29.aspx and the documentation for it under .NET v4: http://msdn.microsoft.com/en-us/library/system.net.webclient%28v=vs.100%29.aspx

    I don't know enough about programming to really interpret the above documentation properly (or know if I'm on the right track).

    Ideally we want that script to function under PowerShell v2 and .NET v2 without having to upgrade things or force PowerShell to use .NET v4. If my suspicion is correct is there is parameter we can specify / a way to modify the script to "fix" this issue?

    Many thanks for any advice.