ServicePointManager SecurityProtocol conflict - c#

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

Related

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.

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;

Override HTTPS certificate

I am using a URL to connect with a web service using SOAP. Apparently the URL does not have a correct https protocol and if I want to access it via browser, I need to accept the 'risk' this connection has.
My problem starts when I want to access in programmatically. When I try to send a SOAP POST request, the connection is closed and an exception is caught.
"The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel."
Apparently this problem was common, and a lot of resources could be found, this and this being the most upvoted.
When i tried this part of code:
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
not only the connection did not work, but now I am given a:
"The remote server returned an error: (500) Internal Server Error."
Now my question is. The code above switches the protocol from https to http?
If not what does this line of code really do?
I don't know if this will be your answer, but as it is not appropriate for a comment...
Do not bypass certificate validation. You probably only need to set the correct version of TLS. You can experiment to find the highest version supported by using one at time instead of OR'ing them together.:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12
If that doesn't work you may need to obtain a certificate, either the one used by the service or one higher in the certificate chain.

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?

Using WCF service in MonoTouch with Authentication

I am using a WCF service client generated by slsvcutil form Silverlight toolkit version 4. I've also tried version 3 with the same problems. When I use a client instance running on http with no user credentials it runs without problems. But I need to switch to https for productive servers and send user credentials that are hardcoded for my application. I use the following code for that:
var binding = new BasicHttpBinding (BasicHttpSecurityMode.TransportCredentialOnly);
var endpoint = new EndpointAddress (AppSettings.FlareEndPoint);
_service = new TopicAnalystAPIClient(binding, endpoint);
_service.ClientCredentials.UserName.UserName = "xxx";
_service.ClientCredentials.UserName.Password = "xxx";
When I call a method on that service pointing to http with no authentication it works. When I use the this code against http/https with the credential I get "There was an error on processing web request: Status code 401(Unauthorized): Unauthorized" exception. I've checked that the credentials are correct, I am able to open the service reference in my browser. I've also tried several combinations of http/https and SecurityMode value. I've also tried it on four different servers always with the same result.
What can be the problem?
A lot of permutations are possible. BasicHttpSecurityMode.TransportCredentialOnly should be usable without SSL [1] using HTTP itself. This means the server will send one (or more) authentication method(s) to the client (e.g. basic, digest, ntlm) and Mono (including MonoTouch) should be providing support for the most of them.
It is possible that the linker (if used) removes one of them. In that case you could try building and testing without linking (or skip linking of System.Net.dll).
It's also possible that the authentication method that the serve insist on is not supported. You could find which one is used by running a network trace (e.g. wireshark) or, maybe, it will show up in more details in the server log (along with the 401 error).
[1] http://msdn.microsoft.com/en-us/library/system.servicemodel.basichttpsecuritymode%28v=vs.95%29.aspx

Categories