The SSL connection could not be established. Authentication failed - c#

I got an error of "The SSL connection could not be established, see inner exception. Authentication failed, see inner exception." when trying to POST request over SSL via C# HttpWebRequest(have tried RestSharp and HttpClient the result is the same). I also tried all the possible resolutions mentioned on the web, like:
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) =>
{ return true; };
ServicePointManager.DefaultConnectionLimit = 9999;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
None of them worked for me. The other issue is that I run the same project on another computer, and it works without any problem. So it looks like that the problem source is the environment, maybe some settings in the .net framework or regedit should be changed. Can anyone help me with this?

The issue might be related to TLS version (see here more information about security protocol types).
An idea is to try using more security protocol types and in case it's working, you can check which protocol you can use:
ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, errors) =>
{ return true; };
ServicePointManager.DefaultConnectionLimit = 9999;
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;

Related

C# could not create ssl/tls secure channel (Restsharp)

I'm currently trying to connect to an api but I am getting this error:
could not create ssl/tls secure channel
The request works when its made through Postman, same endpoint, same certificate and everything, but when I am making the request through restsharp it stops with the SSL/TLS error
I've tried forcing the security protocol to TLS12 with the code:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
Also tried to remove the certificate validation with
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
And some other variations of this code.
Tried to disable it on the client as well, with no success either
client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
So I am currently trying to use Wireshark to get some more information. From what i could understand, it isn't an issue with the cipher suite, since it passes the "Client Hello" and "Server Hello" and it stops on the "Certificate Request, Server Hello Done".
The errors that appear on the image also appear when I make the request with Postman.
It stops on this line when it receives a RST flag with the ACK.
Does anyone have any idea on why it isn't working?
Also it's worth mentioning that I used the same code many times before to call other api's and they seem to work fine. Just this one that I can't make work no matter what I try. I don't have access to the servers since its a third-party api.
Any help on this matter is appreciated.
Edit: To add the code that i use to make the api call and some more info that was asked
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;
ServicePointManager.ServerCertificateValidationCallback += (sender, certificateReturn, chainReturn, sslPolicyErrors) => true;
var client = new RestClient(api);
client.Timeout = -1;
//Add Certificate
X509Certificate2 cert = null;
if (GCONTABANCO.SelectCERTIFICADO(IDCONTABANCO, ref cert, ref MSG) == false) { return false; }
client.ClientCertificates = new X509CertificateCollection();
client.ClientCertificates.Add(cert);
var request = new RestRequest(Method.POST);
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", clientId);
request.AddParameter("client_secret", clientSecret);
request.AddParameter("scope", "extrato.read boleto-cobranca.read boleto-cobranca.write");
IRestResponse response = client.Execute(request);
I'm using .net framework 4.5.2, i tried updating to 4.7 but the error persisted and currently i can't update the version because its a big system and can't risk breaking it
Windows build number: 21H1 (10.0.19043)
So i managed to fix the issue with the help from their IT architect, i'll leave the answer here in case someone runs into the same issue in the future.
Since they had a lot of certificates being sent through the connection, it was going over the limit allowed and closing the connection, so i had to change the limit to be able to connect to the server. In C# it has to be changed on the regedit.
To do so i had to:
Open regedit.
Go to: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Messaging
Then add a MessageLimitClient DWORD value.
Set the value to 65536.
Restart the machine.
After doing that and testing again the connection was successful.

Azure APIM URL throws System.Net.WebException - How SSL/TLS making difference in azure web api and azure APIM?

I have created web api and tried to issue GET request using c# as follow
namespace APIMCheck
{
class Program
{
static void Main(string[] args)
{
string thumbprint = "***";
string url #"https://******-us-stats-webapi.azurewebsites.net/statistics/v1/masterData/carTypes";
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, thumbprint, true);
X509Certificate2 certificate = certificates[0];
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.ClientCertificates.Add(certificate);
req.Method = WebRequestMethods.Http.Get;
Console.WriteLine(Program.CallAPI(req).ToString());
Console.Read();
}
public static string CallAPI(HttpWebRequest req)
{
var httpResponse = (HttpWebResponse)req.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
return streamReader.ReadToEnd();
}
}
public static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true;
}
}
}
I get response with data. All good.
Now, I have created Azure APIM, which will act as front end for above web API
This is policy configured in Azure API Management portal
<policies>
<inbound>
<base />
<choose>
<when condition="#(context.Request.Certificate.Verify() != true || context.Request.Certificate == null || context.Request.Certificate.Issuer != "CN=MySubCA, DC=MYEXT, DC=NET" || context.Request.Certificate.NotAfter < DateTime.Now)">
<return-response>
<set-status code="403" reason="Invalid client certificate" />
<set-body template="none">#(context.Request.Certificate.Issuer.ToString())</set-body>
</return-response>
</when>
</choose>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<base />
</on-error>
</policies>
Now, changed the url as follow to point apim
string url = #"https://******-us-stats-apim.azure-api.net/statistics/v1/masterData/carTypes";
I get below error
The request was aborted: Could not create SSL/TLS secure channel for HttpWebRequest
How SSL/TLS making difference in web api and APIM?
Anything to do with firewall?
By default, TLS 1.2 is enabled for Azure API Management gateway.
You could go to your azure api management(on portal) > Protocol settings> turn on tls 1.2 and ssl 3.0.
There are a few things you do in your test app and APIM cannot do on it's own:
Enable SSL3
Add client certificate
Ignore any SSL validation errors.
Of the things above only #2 is fine to have in production. SSL3 is deprecated and should not be used in production. Ignoring any SSL errors is also unwise, since that way you cannot be sure that you're talking to your server.
Now assuming that you're fine with all of the above:
For SSL3 follow #Joey Cai answer.
To allow APIM to use your certificate to authenticate to backend follow this guidance: https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-mutual-certificates
To control SSL validation at APIM level use this REST API: https://learn.microsoft.com/en-us/rest/api/apimanagement/2019-01-01/backend/createorupdate and set-backend-service policy.
The main reason for #2 and #3 is that client-to-APIM and APIM-to-backend are two separate connections. So when APIM needs to make a call to backend it must have client certificate available (if it's required by backend). That also means that by default APIM will not require client to provide certificate.

.Net core HttpClient bug? SocketException: An existing connection was forcibly closed by the remote host

The following code runs without any error in a full .Net framework console program. However, it got the following error when running in .Net core 2.1.
System.AggregateException
HResult=0x80131500
Message=One or more errors occurred.
Source=System.Private.CoreLib
StackTrace:
at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
at ConsoleApp1.Program.requestString(String url) in C:\source\repos\ConsoleApp1\Program.cs:line 38
at ConsoleApp1.Program.Main(String[] args) in C:\source\repos\ConsoleApp1\Program.cs:line 13
Inner Exception 1:
HttpRequestException: The SSL connection could not be established, see inner exception.
Inner Exception 2:
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Inner Exception 3:
SocketException: An existing connection was forcibly closed by the remote host
Code:
class Program
{
static void Main(string[] args)
{
var url = "https://google.com";
var (statusCode, html) = requestString(url);
Console.WriteLine("%d %s", statusCode, html);
}
static CookieContainer cc = new CookieContainer();
static HttpClientHandler handler = new HttpClientHandler { AllowAutoRedirect = false, CookieContainer = cc };
public static async Task<(int statusCode, string content)> requestStringAsync(string url)
{
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
// | SecurityProtocolType.Ssl3;
using (var request = new HttpRequestMessage { RequestUri = new Uri(url), Method = HttpMethod.Get })
using (var client = new HttpClient(handler))
{
var response = await client.SendAsync(request); // Error (actual line)
// response.EnsureSuccessStatusCode() |> ignore
var statusCode = (int)response.StatusCode;
var content = await response.Content.ReadAsStringAsync();
return (statusCode, content);
}
}
public static (int statusCode, string content) requestString(string url)
{
return requestStringAsync(url).Result;
}
}
There is a bug for .NET Core 2.1 Preview mentioning this issue. That may be the cause. However, I also notice that your setting of TLS is incorrect. You're currently enabling it, but overwriting all other protocols that have been set. Instead of this:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
You should be using this:
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
// ----------------------------------^
I think that's a side issue, but worth fixing all the same.
Update
The referenced GitHub issue above has a discussion which eventually links to the official announcement for .NET Core 2.1 SDK Preview 2. It has the following to say:
Sockets Performance and SocketsHttpHandler
We made major improvements to sockets in .NET Core 2.1. Sockets are the basis of both outgoing and incoming networking communication. The higher-level networking APIs in .NET Core 2.1, including HttpClient and Kestrel, are now based on .NET sockets. In earlier versions, these higher-level APIs were based on native networking implementations.
...
You can use one of the following mechanisms to configure a process to use the older HttpClientHandler:
From code, use the AppContext class:
AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
The AppContext switch can also be set by config file.
The same can be achieved via the environment variable DOTNET_SYSTEM_NET_HTTP_USESOCKETSHTTPHANDLER. To opt out, set the value to either false or 0.
In my case the root cause was using multiple concurrent calls of HttpClient.GetAsync(url). I fixed it by making HttpClient instance as singleton.
More info here.
Therefore, HttpClient is intended to be instantiated once and reused throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. That issue will result in SocketException errors. Possible approaches to solve that problem are based on the creation of the HttpClient object as singleton or static...

How to use TLS 1.2 in ASP.NET Core 2.0

My salesforce res apis were working fine until. When suddenly I started getting authentication errors. retry your request.
Salesforce.Common.AuthenticationClient.d__1.MoveNext().
salesforce informed that it would use from now TLS .1.2. How can I enforce my asp.net core 2.0 to use TLS 1.2 in Startup.cs. below is my code for login.
private async Task<AuthenticationClient> GetValidateAuthentication()
{
RestApiSetting data = new RestApiSetting(Configuration);
var auth = new AuthenticationClient();
var url = data.IsSandBoxUser.Equals("true", StringComparison.CurrentCultureIgnoreCase)
? "https://test.salesforce.com/services/oauth2/token"
: "https://login.salesforce.com/services/oauth2/token";
try
{
//ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
await auth.UsernamePasswordAsync(data.ConsumerKey,
data.ConsumerSecret, data.Username, data.Password, url);
return auth;
}
catch (Exception ex)
{
throw new Exception(ex.ToString());
}
}
.net framework prior to version 4.7 makes outbound connections using TLS 1.0 by default. You can upgrade to a newer version to fix the problem, or alternatively, you can set the default and fallback versions for outbound calls using the ServicePointManager, or passing the setting into the HttpClient if you have the source code for the library.
Add the following somewhere early in your pipeline, such as your startup.cs or global.asax:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
You can find a good description on the topic here: https://social.msdn.microsoft.com/Forums/en-US/8db54c83-1329-423b-8d55-4dc6a25fe826/how-to-make-a-web-client-app-use-tls-12?forum=csharpgeneral
And if you want to specify it only for some requests instead of application-wide, then you can customize the HttpClientHandler of your HttpClient:
var handler = new HttpClientHandler
{
SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls
};
HttpClient client = new HttpClient(handler);
...
According to the following
https://github.com/dotnet/corefx/issues/29452
In .NET Core, ServicePointManager affects only HttpWebRequest. It does not affect HttpClient. You should be able to use HttpClientHandler.ServerCertificateValidationCallback to achieve the same.

SSL/TLS error with HTTPClient

I am trying to connect to internal website that is using properly signed SSL certificate (works in Chrome 58) but when I execute this code in .Net it throws error:
The Request was aborted: Could not create SSL/TLS channel.
ServicePointManager.MaxServicePointIdleTime = 0;
ServicePointManager.Expect100Continue = true;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls
| SecurityProtocolType.Tls11
| SecurityProtocolType.Tls12
| SecurityProtocolType.Ssl3;
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, "https://internal-website");
request.Headers.Add("token", "---");
var result = client.SendAsync(request);
result.Wait();
The only reason I can think of is the fact that certificate is using Subject Alternative Name for DNS names (it has 4 entries there) and CN doesn't match any of them but it still works in Chrome and Postman.
The code that I've added before creating HttpClient was to disable SSL check but it didn't work any ideas how I can debug this issue?
After quite a bit of investigation, it turned out to be a problem with the length of DHE key.
.Net and IE require DHE to be greater or equal to 1024 but for this service, the key was 512. Reference to Microsoft KB
If changing key length on the server is not possible you can change registry on the user machine.
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\KeyExchangeAlgorithms\Diffie-Hellman]
"ClientMinKeyBitLength"=dword:00000200

Categories