How does ServicePointManager.SecurityProtocol work? - c#

I would like to know how the property ServicePointManager.SecurityProtocol works when I set three different SecurityProtocolType on her flags. I.E:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
Will the communication try first to communicate with TLS, and if it fails try TLS1.2 and after SSL3?
If not, what do these flags mean and how does it work?

Whichever communication object you're using (HttpClient, HttpWebRequest, etc) will try to negotiate to the highest level possible first. Failing that it will keep going "down" the chain.
If you're using .Net 4.6 then the default security protocols will look like this because SSL3 is broken:
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12
If you really need to use SSL3 for some reason and are using .Net 4.6, see this MS KB article on how to force it to be insecure: https://support.microsoft.com/en-us/kb/3069494
You might also be asking how this protocol level is actually determined? This is step 1 of the SSL handshake process where each end of the connection says "I support this version". Here is an interesting read on the full handshake process: http://www.truedigitalsecurity.com/blog/2015/05/20/ssltls-protocol-version-negotiation/

Related

How do you enable TLS 1.2 on C# for kafka producer/consumer config?

I want to set communication over TLS1.2 in C#
in java we do it by setting this property "ssl.enabled.protocols" looking for same functionality in c#
I'm using .Net core 3.1 and OS is linux
package : confluent.Kafka version 1.7.0
If you are using some web client or smtp email sender you can add this line before request
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Put this somewhere at or near the very beginning of execution:
System.Net.ServicePointManager.SecurityProtocol =
SecurityProtocolType.Tls12
// Only if you need them -
// | SecurityProtocolType.Tls13
// | SecurityProtocolType.Tls11
// | SecurityProtocolType.Tls
;
Contrary to the misinformation in some of the comments above and below, it is not always guaranteed that TLS 1.2 will be on in every environment that it's available. Of course this is more of an issue for older OS's and .NET versions, but that doesn't mean TLS 1.2 can't be used - it just means you have to set it up explicitly.
Many sources will tell you this has to be done in the Windows registry in older environments, but you can also enable it through the code above.
See also this thread for additional detail.
Edit - After the OP's clarifying comment, I changed the |= to '=' because they actually want to DISABLE any TLS version besides 1.2.

Https leads to exception using HttpClient

I have a problem calling my ASP.NET Web API from a client application. Many questions regarding this topic were asked here but none of the answers solved my issue.
Problem:
When I try to call my API I get the following exception:
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
Info:
Both projects (cleint and API) are based on .NET 4.5.2
In my test environment client and API are running on the same VM
Everything worked fine wihtout https
I created a selfsigned certificate for testing purposes but no browser shows a warning so it seems to be fine
Code:
HttpClient client = new HttpClient();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
client.BaseAddress = new Uri(apiBaseUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync("call/CreateNew", call);
I tried several solutions provided in the answers of similar questions, but none of these worked so far:
Using .NET Framework 4.6 instread of 4.5.2
Specified the protocol with ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Tried ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; (just to be sure)
In another question someone suggested using Wireshark to further analyze the problem. I gave it a try but I have to admit that I did not really know what I was doing.
Anyway I found segments that said "ACKed segment that wasn't captured" and "Previous segment(s) not captured" of which the second contained data I actually tried to send to my API.
Can you give me some advice what to try next or how to fix this error?

Multi-threaded SSL / TLS version switching

We have Wcf service (core service) consumed by an asp.net mvc. This core service integrate with other third-party services to achieve some use cases. All these third-party service endpoints are exposed via https but differs when it comes to the supported SSL/TLS versions (1.0,1.1,1.2).
We don’t have much control over this and simply stick a specific ( supported ) SSL/TLS version just before connecting with any given third-party service. i.e. Whenever the core service want to consume any third party service, it set the ServicePointManager.SecurityProtocol to supported SSL/TLS version (third-party ask us to connect using version x.x or higher).
// brief expression of logic which switch TLS version 1.2
var currentSecurityProtocol = ServicePointManager.SecurityProtocol; // get the current security protocol.
try
{
ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
//now get/post data to/from third party service
}
catch (Exception ex)
{
//report it
}
finally
{
ServicePointManager.SecurityProtocol = currentSecurityProtocol;
ServicePointManager.ServerCertificateValidationCallback = null;
}
Question:
How to re-implement the above of TLS version switching logic to work
seamlessly on multi-threaded environment?
I managed to write logic which synchronize access through a lock on ServicePointManager.SecurityProtocol property. But this attempt affect the performance of other connected clients ( when they consume any other third party offering/ service)
You could specify multiple version of Tls so that you don't need to change it during runtime. The below code means that it support TLS1.0, TLS1.1 and TLS1.2.
If the client supports TLS1.2 or below, TLS1.2 is used to create a connection
If the client support TLS1.1 or below, the highest available security protocol which is TLS1.1 is used.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;

Logging Security Protocol for C# HttpWebRequest

I have a daemon that makes outbound WebRequests based on information from a database. It is written in C# using .net 4.6. I have modified the initialization of my process to set:
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
This all works correctly. I now would like to add some logging to see what various security protocols I'm using on the outbound connections. I'm thinking, "established tls 1.2 connection to https://www.google.com"
My problem is at the level of HttpWebRequest, I don't appear to be able to get information about the SecurityProtocol. I can get things about the server certificate:
ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateRemoteCertificate);
So inspecting the certificate, I can log things like:
FriendlyName "sha256RSA" string
Value "1.2.840.113549.1.1.11” string //I do not believe this version number corresponds to the TLS version, I believe this is the version of the SHA256 encryption algorithm.
Is it possible to get information about the security protocol? Also, is it possible to get access to the underlying SslStream object inside the HttpWebRequest?

ServicePointManager SecurityProtocol conflict

In my app I use the RestSharp to query a REST API and System.Net.Mail to send emails. On the program startup I set the ServicePointManager.SecurityProtocol property.
If I set the property to:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
Exception is thrown when querying API with RestSharp:
The request was aborted: Could not create SSL/TLS secure channel
If I set the property to:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls11;
Exception is thrown when sending email with System.Net.Mail:
System.Security.Authentication.AuthenticationException: A call to SSPI failed, see inner exception. ---> System.ComponentModel.Win32Exception: The client and server cannot communicate, because they do not possess a common algorithm
How should I resolve this issue?
The REST API server and the mail server you are connecting to apparently have conflicting security protocol requirements. You'll need to use different security protocol settings for them.
ServicePointManager.SecurityProtocol is static and its current value applies to all new connections. There is unfortunately no way to control this setting per ServicePoint. (In my opinion this is a design flaw from Microsoft)
If you have control of either the REST API server or the mail server, then you could perhaps reconfigure them to accept non-conflicting security protocols.
Otherwise, you could re-design your code so that all connections to the REST API and the mail server are made from two separate AppDomains.
For example let the default app domain handle all REST API communication and spawn a separate app domain that does all the mail communication.
With this setup you can use different ServicePointManager.SecurityProtocol values in each domain. (since static values are not shared between app domains).

Categories