Multi-threaded SSL / TLS version switching - c#

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;

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.

Bypass invalid SSL certificate errors .Net / c#

I've got a development system which I'm trying to get to communicate to a third-party secure web service.
The third party have provided me with a certificate which I've imported locally. I've made sure the certificate is added to the 'Trusted Root Certification Authorities' store. It seems to have imported correctly, as if I go Chrome and try to access one of the service urls mentioned in the web service WSDL file I firstly get a popup asking to me to confirm which certificate to use (there's only the one option) and it then lets me through. However, if I then use the same WSDL file to create a service reference in Visual Studio, and make a call to one of the services in my code, I get an error saying 'Could not establish secure channel for SSL/TLS with authority'.
Ideally I would get VS to acknowledge the cert when I'm making the webservice call, but seeing as this is a development system I'm also happy to ignore the SSL errors for the time being.
To this end I've added the following to my code, along with variations on the protocols I'm specifying (e.g. only specifying SSL3, taking out SSL3 etc):
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
But no matter what I do I still get the SSL error when I try to make the service call.
If anyone has any suggestions on how to get VS to accept the certificate is present (as Chrome seems to do) or, alternatively, how to get the code to ignore the SSL error for now, so I can proceed with development, it'd be much appreciated.

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).

Which versions of SSL/TLS does System.Net.WebRequest support?

Now that SSL 3 has been found to be vulnerable to the POODLE attack:
Which versions of SSL/TLS does System.Net.WebRequest use when connecting to any https Uri?
I use WebRequest to connect to several 3rd party API's. One of these has now said they will block any request that uses SSL 3. But WebRequest is part of the .Net core framework (using 4.5) so it is not obvious what version it uses.
This is an important question. The SSL 3 protocol (1996) is irreparably broken by the Poodle attack published 2014. The IETF have published "SSLv3 MUST NOT be used". Web browsers are ditching it. Mozilla Firefox and Google Chrome have already done so.
Two excellent tools for checking protocol support in browsers are SSL Lab's client test and https://www.howsmyssl.com/ . The latter does not require Javascript, so you can try it from .NET's HttpClient:
// set proxy if you need to
// WebRequest.DefaultWebProxy = new WebProxy("http://localhost:3128");
File.WriteAllText("howsmyssl-httpclient.html", new HttpClient().GetStringAsync("https://www.howsmyssl.com").Result);
// alternative using WebClient for older framework versions
// new WebClient().DownloadFile("https://www.howsmyssl.com/", "howsmyssl-webclient.html");
The result is damning:
Your client is using TLS 1.0, which is very old, possibly susceptible to the BEAST attack, and doesn't have the best cipher suites available on it. Additions like AES-GCM, and SHA256 to replace MD5-SHA-1 are unavailable to a TLS 1.0 client as well as many more modern cipher suites.
That's concerning. It's comparable to 2006's Internet Explorer 7.
To list exactly which protocols a HTTP client supports, you can try the version-specific test servers below:
var test_servers = new Dictionary<string, string>();
test_servers["SSL 2"] = "https://www.ssllabs.com:10200";
test_servers["SSL 3"] = "https://www.ssllabs.com:10300";
test_servers["TLS 1.0"] = "https://www.ssllabs.com:10301";
test_servers["TLS 1.1"] = "https://www.ssllabs.com:10302";
test_servers["TLS 1.2"] = "https://www.ssllabs.com:10303";
var supported = new Func<string, bool>(url =>
{
try { return new HttpClient().GetAsync(url).Result.IsSuccessStatusCode; }
catch { return false; }
});
var supported_protocols = test_servers.Where(server => supported(server.Value));
Console.WriteLine(string.Join(", ", supported_protocols.Select(x => x.Key)));
I'm using .NET Framework 4.6.2. I found HttpClient supports only SSL 3 and TLS 1.0. That's concerning. This is comparable to 2006's Internet Explorer 7.
Update: It turns HttpClient does support TLS 1.1 and 1.2, but you have to turn them on manually at System.Net.ServicePointManager.SecurityProtocol. See https://stackoverflow.com/a/26392698/284795
I don't know why it uses bad protocols out-the-box. That seems a poor setup choice, tantamount to a major security bug (I bet plenty of applications don't change the default). How can we report it?
When using System.Net.WebRequest your application will negotiate with the server to determine the highest TLS version that both your application and the server support, and use this. You can see more details on how this works here:
http://en.wikipedia.org/wiki/Transport_Layer_Security#TLS_handshake
If the server doesn't support TLS it will fallback to SSL, therefore it could potentially fallback to SSL3. You can see all of the versions that .NET 4.5 supports here:
http://msdn.microsoft.com/en-us/library/system.security.authentication.sslprotocols(v=vs.110).aspx
In order to prevent your application being vulnerable to POODLE, you can disable SSL3 on the machine that your application is running on by following this explanation:
https://serverfault.com/questions/637207/on-iis-how-do-i-patch-the-ssl-3-0-poodle-vulnerability-cve-2014-3566
I also put an answer there, but the article #Colonel Panic's update refers to suggests forcing TLS 1.2. In the future, when TLS 1.2 is compromised or just superceded, having your code stuck to TLS 1.2 will be considered a deficiency. Negotiation to TLS1.2 is enabled in .Net 4.6 by default. If you have the option to upgrade your source to .Net 4.6, I would highly recommend that change over forcing TLS 1.2.
If you do force TLS 1.2, strongly consider leaving some type of breadcrumb that will remove that force if you do upgrade to the 4.6 or higher framework.

Categories