SSL Handshake fails from asp.net application - works in browser - c#

I am trying to do a simple get request using the System.Net.Http.HttpClient (using GetStringAsync). The request fails when done from my webapi asp.net application, but it works correctly from the browser and postman.
The request fails with Authentication failed because the remote party has closed the transport stream.
Note: It works correctly when doing get request to other servers using TLS.
I used the following to confirm that the issue was with ssl. Using these two lines makes the request work, but obviously disabling certificate validation is not a real solution.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
I tested the server using https://www.ssllabs.com and it seems that
everything is working correctly on there. It supports TLS 1.1 and 1.2.
To find out what is going on I was looking at the packages in wireshark, but since I don't know much about ssl, I am not learning much. Looking at the packages from the browser request I can see that it is using the TLS 1.2 protocol and that the handshake looks correct.
The following picture shows the client initiating two separate ssl "ClientHello's". For some reason the server doesn't respond with a SSL handshake response.
Hope someone can help me figure out what is going on.

I tested the server using https://www.ssllabs.com and it seems that everything is working correctly on there. It supports TLS 1.1 and 1.2.
Your client is doing a TLS 1.0 handshake only. If the server supports only TLS 1.1 and TLS 1.2 but not TLS 1.0 the connection will fail. Since modern browsers all support TLS 1.2 browsers will work.

Related

Is it possible to modify TLS handshake in C# HttpClient on .NET Core

Apparently, CloudFlare now has some kind of a whitelist for the possible TLS handshake parameters for every known browser.
Thus, when I'm sending HTTPS requests using HttpClient, CloudFlare considers it a bot and at the very minimum presents a captcha.
The captcha itself is not a problem, I'm using a browser to ask the user to pass it. However, some websites apparently block some requests even after passing the captcha just because the TLS handshake was not whitelisted by CloudFlare.
So I've digged into the .NET Core source to see if I can modify the way TLS handshake packet is built. Unfortunately, it seems that .NET Core itself doesn't build it itself but rather delegates it to the underlying library (OpenSSL on Linux / standard Windows)...
Is the only solution to write my own SSL library?... Sounds like a task for many months.

Strange TLS client cert handshake issue with C# ASP.Net Core app

I have a strange problem. The app in question is:
ASP.Net Core 2.2 running on .Net Framework 4.7.2
Running under IIS 8.5 unmanaged
This app has to contact a REST service in the background. This REST service requires a client cert. I use System.Net.Http.HttpClient to connect to the REST service using the client cert over TLS 1.2.
This works. However, after a day or so, it just stops working and returns
The request was aborted: Could not create SSL/TLS secure channel
Even restarting the IIS app doesn't fix this. It usually just starts working again and I can't work out the circumstances which lead to this. Rebooting the server doesn't even necessarily fix it. The remote REST app has no issues with the (many) other client libs talking to it. I have exactly the same issue in DEV/TRAIN and PROD instances of the same app. Just to be clear, it does work, it just suddenly stops working after some time so I know the client cert works and TLS 1.2 works. I also use TLS 1.2 and the exact same client cert to the same REST endpoint in several other apps in completely different languages (PowerShell, perl) without any problems at all.
I cannot work out what is happening. I have tried reading the client cert from the filesystem before every REST call and also reading it once in the Startup class and injecting it. Both approaches have the same issue.
Now, one thing I am suspicious of is that this client REST call is not running async as it's in a static method but I can't see how that would have this result. If I look at the remote server logs for the REST endpoint, I see an error saying that no client certificate was supplied. I have put in debugging to write the client cert thumbprint in my local app logs just before the REST call to make sure that the client cert is really there for the call and it is - the logs always contain the correct client cert thumbprint in the logs just before the failed REST call.
Update: I modified the REST call so that it is async and it makes no difference. I am now reusing one instance of HttpClient with the client cert loaded and still this error starts to happen after a while.
Any ideas much appreciated.

Force HttpWebRequest and ClientWebSocket to use TLS 1.2

I´m trying to connect to a websocket with the ClientWebSocket class. I´m using Unity 2017.4.10. Unfortunately C#/Mono is always using TLS 1.0 which for some reason fails. When i examine the connection with Wireshark i get a encrypted alert packet and the connection closes.
I already tried to force TLS 1.2 by setting:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
but still the WebSocket tries to connect with TLS 1.0.
When connecting to wss://echo.websocket.org it works, as websocket.org only supports TLS 1.2. Unfortunately my provider still supports TLS 1.0 1.1 and 1.2.
No matter what i try TLS 1.0 is always used by HttpWebRequest and ClientWebSocket classes.
I know TLS 1.0 is used because Wireshark and Fiddler says so.
Looks like this is a unity bug and fixed in 2018.2
Issue
for Websocket try :
WebSocketClient.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12;

Packets not being captured when negotiating TLS versions with .NET SslStream

My set up is:
I have a server listener app that only accepts TLS 1.0 connections.
I have a client app that uses SslStream.AuthenticateAsClient to configure a secure connection
I am using WireShark to monitor traffic between client and server
On the client machine I use the SecurityProviders\SCHANNEL\Protocols registry keys to manipulate which version of TLS I want to use. If I force the client to use TLS 1.2 I get the expected error of "The client and server cannot communicate, because they do not possess a common algorithm". However, the only packets that get captured in WireShark are the TCP 3-way handshake.
Conversely, if I explicitly specify Tls1.2 in the call to SslStream.AuthenticateAsClient I see the Client Hello and Server Hello TLS messages in WireShark. And of course, I see the same expected error message as above.
My question is, when I'm only using the Registry to manipulate TLS versions how come I do not see any TLS packets being sent through WireShark? How does Windows/.NET know that the remote server does not support TLS 1.2?
Thanks

WCF service (self-hosted) over HTTPS - Get negotiated SSL/TLS protocol version

Due to security reasons, we wanted to disable TLS 1.0 support in our server on OS level (in followign SChannel registry):
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols
But because the SQL Server service won't start with TLS 1.0 disabled, we had to leave the TLS 1.0 enabled on OS level.
What we are trying to do now is to force the usage of TLS 1.2 on application level rather than on OS level.
Our application is Client-Server, running on .NET 4.5.
On the Client, before calling the WCF service, we set:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
That ensures that the Client will send ClientHello message with TLS1.2 protocol.
But on the Server, which is self-hosted WCF service, we do not see how to force the TLS1.2 usage. The SSL/TSL negotiation on the Server side is based on the SChannel registry and thus setting the ServicePointManager.SecurityProtocol does not make any effect.
We would like to inspect the incoming WCF call in our Server code and check what TLS protocol used for the call, and close the connection if it is anything less than TLS1.2.
Is there any way how to get the incoming WCF call SSL/TLS protocol version? Something like HttpContext.WebSocketNegotiatedProtocol?
Have you tried using a custom binding with sslStreamSecurity?
<sslStreamSecurity requireClientCertificate="false" sslProtocols="Tls12" />

Categories

Resources