title: Invoke-WebRequest Always Fails For HTTPS. The remote certificate is invalid according to the validation procedure
body: <p>I'm trying to use Invoke-WebRequest inside of <code>pwsh</code> (on Linux), but it's always failing. Here's an example:</p>
  <pre><code>    Invoke-WebRequest https://www.google.com
  </code></pre>
  <p>The site/URL doesn't matter, if it's using HTTPS I'll get the error. The exact same script on a Windows machine works without issue.</p>
  <p><strong>$PSVersionTable</strong></p>
  <pre><code>&gt; Name                           Value
  &gt; ----                           -----
  &gt; PSVersion                      7.0.0
  &gt; PSEdition                      Core
  &gt; GitCommitId                    7.0.0
  &gt; OS                             Linux 3.10.0-514.21.1.el7.x86_64 #1 SMP Thu May 25 17:04:51 UTC 2017
  &gt; Platform                       Unix
  &gt; PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0…}
  &gt; PSRemotingProtocolVersion      2.3
  &gt; SerializationVersion           1.1.0.1
  &gt; WSManStackVersion              3.0
  </code></pre>
  <p><strong>dotnet --version</strong></p>
  <blockquote>
  <p><code>3.1.403</code></p>
  </blockquote>
  <p><strong>openssl version</strong></p>
  <blockquote>
  <p><code>OpenSSL 1.0.1e-fips 11 Feb 2013</code></p>
  </blockquote>
  <p>I know it's possible to disable SSL validation on the Invoke-WebRequest method but I'd really rather avoid it and, also, I'm seeing the same issue when doing things like <code>dotnet restore</code></p>
  <p>If I use <code>curl https://www.google.com</code> it seemingly works fine. My understanding was that pwsh uses dotnet to actually make this webrequest, and that dotnet uses openssl for https...that might all be wrong, but I've been trying to debug this using openssl.</p>
  <p>When I do <code>openssl s_client -connect www.google.com:443</code> it seems to show that everything is fine. I can see the certificate chain:</p>
  <pre><code>&gt; Certificate chain  
  &gt;  0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com    
  &gt;    i:/C=US/O=Google Trust Services/CN=GTS CA 1O1
  &gt;  1 s:/C=US/O=Google Trust Services/CN=GTS CA 1O1    
  &gt;    i:/OU=GlobalSign Root CA - R2/O=GlobalSign/CN=GlobalSign
  </code></pre>
  <p>And the return code of 0 (ok)</p>
  <pre><code>Start Time: 1612285043
  Timeout   : 300 (sec)
  Verify return code: 0 (ok)
  </code></pre>
  <p>If I catch the exception in my <code>.ps1</code> script I can see a little more information:</p>
  <pre><code>The remote certificate is invalid according to the validation procedure.
  System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
   ---&gt; System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
     at System.Net.Security.SslStream.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
     at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
     at System.Net.Security.SslStream.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
  --- End of stack trace from previous location where exception was thrown ---
     at System.Net.Security.SslStream.ThrowIfExceptional()
     at System.Net.Security.SslStream.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
     at System.Net.Security.SslStream.EndProcessAuthentication(IAsyncResult result)
     at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
     at System.Net.Security.SslStream.&lt;&gt;c.&lt;AuthenticateAsClientAsync&gt;b__65_1(IAsyncResult iar)
     at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
  --- End of stack trace from previous location where exception was thrown ---
     at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
     --- End of inner exception stack trace ---
     at System.Net.Http.ConnectHelper.EstablishSslConnectionAsyncCore(Stream stream, SslClientAuthenticationOptions sslOptions, CancellationToken cancellationToken)
     at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
     at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
     at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
     at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
     at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.GetResponse(HttpClient client, HttpRequestMessage request, Boolean keepAuthorization)
     at Microsoft.PowerShell.Commands.WebRequestPSCmdlet.ProcessRecord()
  </code></pre>
  <p>But I'm still at loss for where to go next.</p>
  <p>Finally - while I can't pinpoint what has changed, I know this <em>used to work</em> on this machine. I was tempted to upgrade everything to the latest versions but it's hard to justify that sort of change when it was working with the versions I have now.</p>
  <p>Can anyone help point me in the right direction?</p>
  <p><strong>EDIT</strong></p>
  <p>Additional information - when I run <em><strong>curl -verbose <a href="https://www.google.com" rel="nofollow noreferrer">https://www.google.com</a></strong></em> I see which cert is being used:</p>
  <pre><code>* Connected to www.google.com (74.125.195.105) port 443 (#0)
  * Initializing NSS with certpath: sql:/etc/pki/nssdb
  *   CAfile: /etc/pki/tls/certs/ca-bundle.crt
    CApath: none
  * SSL connection using TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  </code></pre>
  <p>I didn't see an equivalent for openssl's s_client, but running <strong>strace -e open openssl s_client -connect <a href="http://www.google.com:443" rel="nofollow noreferrer">www.google.com:443</a> |&amp; grep open</strong> shows:</p>
  <pre><code>open(&quot;/etc/pki/tls/openssl.cnf&quot;, O_RDONLY) = 3
  open(&quot;/etc/pki/tls/cert.pem&quot;, O_RDONLY) = 3
  </code></pre>
  <p>But I haven't been able to see <code>pwsh</code> attempting to access any of the root ca's I have installed. When I search online, I just see a lot of people saying that dotnet core on Linux uses OpenSSL and that I should look at the <code>openssl.cnf</code> file - but when I use openssl from the command line, it seems to work?!?</p>
  <p>Again - any help would be greatly appreciated it. It seems like pwsh just isn't using the certs I have?</p>