1

I am facing an issue while making a REST call by using HttpClient object.

  1. I have an application developed in .NET Core that runs on a Windows and Linux machine.
  2. This application makes a call to https://dev.example.com/.
  3. The SSL certificate is valid, and it has all required intermediate and chained certificates.
  4. This certificate is issued for all the URLs that have the domain *.example.com. That means the same certificate should work for dev.example.com, test.example.com, stage.example.com, and also for prod.example.com.
  5. The .NET core application is working fine when we execute it on a Windows 10 machine. However we face issues when we execute it on a Windows 7 machine.

I also tried to use the certificate file (.cer) while sending the request by using the HttpClientHandler class. On the Windows 7 machine, I also tried to download the certificate and added it in the trusted certificates. However, I still face the issue.

Below is the stack trace.

ERROR ======================= :: System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.
   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslState.ThrowIfExceptional()
   at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsClient(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsClientAsync>b__47_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.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.CreateConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Net.Http.HttpConnectionPool.WaitForCreatedConnectionAsync(ValueTask`1 creationTask)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   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.FinishSendAsyncBuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)

Update

I tried to get the certificate information with IE web browser.

On the Windows 10 system, I can see the complete certificate information. However, on the Windows 7 system I can see the message as

The certificate cannot be verified up to a trusted certificate authority

Michael
  • 8,362
  • 6
  • 61
  • 88
Avinash
  • 1,363
  • 2
  • 15
  • 28
  • Have you checked this -> https://stackoverflow.com/questions/777607/the-remote-certificate-is-invalid-according-to-the-validation-procedure-using – LIvanov Oct 07 '20 at 06:03
  • 1
    Are the root certificates up to date on that Windows 7 box? Your certificate might be okay but if the root or intermediate certs are invalid it still won't work. You can verify that if you open the certificate from the certmgr.msc on the windows 7 box and then check the certificate chain. See https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/dn265983(v=ws.11)?redirectedfrom=MSDN if you find that certificates are missing in that chain. – rene Oct 07 '20 at 06:35
  • Hi Rene, the certificates are verified on the SSL check sites like aboutssl.org and https://www.sslshopper.com/. According to these sites, the root certificate, intermediate, and chained certificates are valid. – Avinash Oct 07 '20 at 06:39
  • Hi LIvanov, I have checked this post, however, this discusses the solution where we can ignore the certificate validations. Also, I think this solution is for the SMTP client and not for the HTTP REST calls. The only option remaining is to use the app.config file option suggested by Sebastian – Avinash Oct 07 '20 at 06:42
  • Stacktrace please. – shingo Oct 07 '20 at 06:43
  • Is your website configured to only accept TLSV1.3 by any chance? – rene Oct 07 '20 at 06:50
  • 3
    @Avinash Rene's question was specifically about the cert chain *on the failing box*; it doesn't matter if sites like aboutssl.org have an up to date cert chain; what matters is whether *your box does*; a cert can be theoretically valid, but if the box you're on doesn't have the relevant root/intermediate certs: it can't know that (note: web browsers don't necessarily use the OS certs in all cases; they can have some additional ones bundled in the install, so even checking from a browser on that box can be different) – Marc Gravell Oct 07 '20 at 06:53
  • @MarcGravell, Thanks for the suggestion. I am not sure whether the box is having relevant root/intermediate certs. I will verify it by using certmgr.msc. One more point, if I open the URL in the Internet Explorer, it shows me the certificate issue. Though I import it as a trusted certificate. – Avinash Oct 07 '20 at 07:02
  • @Avinash that's a good clue that the Windows certificate store has a problem with the chain indeed. You may need to import the root and intermediate certificate, not the actual end one. (add the root to the trusted certificates for instance) – Pac0 Oct 07 '20 at 07:19
  • @rene, I have verified the certificate in the Trusted Root Certificate Authorities and also verified the certificate chain. I got the message "Windows does not have enough information to verify the certificate" when I tried to open it and see the certificate chain. In the certificate chain, I can see the "Issued To" field is for *.mybackendapp.com (Name changed due to security). – Avinash Oct 07 '20 at 07:39
  • you need to get the certificate chain and install those on that win7 box in the right cert stores. Check the link in my first comment for more support on that. – rene Oct 07 '20 at 08:11
  • You can [turn on the networking tracing](https://learn.microsoft.com/en-us/dotnet/framework/network-programming/how-to-configure-network-tracing), when the exception throws you will get the exact error message and the certificate in the log. – shingo Oct 07 '20 at 08:16
  • @shingo, I tried to create the network tracing configuration file as per the documentation. However, the log file is not getting created in the given location. The config file name initially I tried to use it MyApplication.exe.config file. But no logs were getting generated, so changed it to MyApplication.config file. I was trying to get the logs on C:\network.log file – Avinash Oct 08 '20 at 11:33
  • MyApplication.exe.config is the right name. Just use the example in the link, it should work, the log will be generated at the working directory. If the config is created by yourself don't forget the xml declaration. – shingo Oct 08 '20 at 11:50

1 Answers1

1

Finally, I was able to resolve the issue.

I found that the service was getting created by one user on the Windows 7 system, however, it was getting called by another user.

I tried to execute the application through the console (command prompt) and found that the application was able to make the calls over HTTPS. However, it was not able to do it when we run it as a service.

Modified the service configuration while creating by using sc command.

sc create <servicename> binPath= <path/to/your/appexe.exe> obj= <username> password= <password>

We this change the application was able to make the calls over HTTPS.

Avinash
  • 1,363
  • 2
  • 15
  • 28