0

I am trying to connect to an API that requires two way SSL configured. I have the the certificate and the private key which I configured in postman as shown in the below image.

enter image description here

This works fine in Postman, but SSL fails when I try to implement it in C# using HttpClient. The error that I get is "The message received was unexpected or badly formatted.". I believe it has something to do with incorrect configuration.

I have referred this StackOverflow post to implement my code: Associate a private key with the X509Certificate2 class in .net

Below is what I have tried:

byte[] publicCertificateBytes = File.ReadAllBytes("<Public Certificate>");
var publicCertificate = new X509Certificate2(publicCertificateBytes);

byte[] privateKey = Convert.FromBase64String(File.ReadAllText("<private key file>").Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", ""));

using (var rsa = RSA.Create())
{
    rsa.ImportPkcs8PrivateKey(privateKey, out _);
    publicCertificate = publicCertificate.CopyWithPrivateKey(rsa);
    publicCertificate = new X509Certificate2(publicCertificate.Export(X509ContentType.Pkcs12));
}

var httpService = new GenericUtilityManager().ResolveUtility<IHttpService>();
var handler = new HttpClientHandler();
handler.SslProtocols = SslProtocols.Tls12;
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(publicCertificate);
handler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
httpService.InitializeHttpClientHandler(handler);

Please help.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • I would suggest comparing the request that goes out from postman to what it becomes when it is called from code. Using fiddler or some intercepting tool will be of help. – shahkalpesh May 25 '21 at 12:19
  • Why are you using `handler.SslProtocols = SslProtocols.Tls12;`? This says `don't use TLS1.3 even if the server requires it`. By default, .NET Core (at least since 4.6.2) will use the best available encryption version. As for the error, it means the client and server couldn't agree on the encryption settings. *Restricting* the settings with `handler.SslProtocols = SslProtocols.Tls12;` can cause that. – Panagiotis Kanavos May 25 '21 at 12:20
  • @shahkalpesh I tried intercepting with wireshark. When I try with postman I get to see the entire SSL handshake happening smoothly. However my app sends a TLS Alert : "Alert (Level: Fatal, Description: Protocol Version)" and then a RST, ACK. ALso on the windows event viewer I get this : "A fatal error occurred while creating a TLS client credential. The internal error state is 10013.". I am not sure what the issue is. My project is on .Net 5.0. – Sreejith Krishnadas May 26 '21 at 11:51
  • @PanagiotisKanavos TLS1.2 is mandatory for this project. Hence the specification. – Sreejith Krishnadas May 26 '21 at 11:52
  • Which OS version are you using? The Windows versions still in mainstream support (Windows 10, Windows Server 2016 and latter) support TLS1.2 directly. All previous versions need patching. This is documented and quite a few similar questions were asked back in 2016 when major services started requiring TLS1.2 – Panagiotis Kanavos May 26 '21 at 12:20
  • Windows 10 Home, Build 19042.985 – Sreejith Krishnadas May 26 '21 at 12:22
  • I see. I also tried adding the registry keys manually mentioned in the link that you shared. They were not there intially. – Sreejith Krishnadas May 26 '21 at 12:25
  • DON'T DO THAT!!!!!!!!! DON"T TRY RANDOM THINGS THAT DON'T APPLY TO THE OS! The only thing you can do is *break it*. .NET isn't broken. TLS isn't broken. Windows isn't broken, but you can break it if you modify the registry. Applications have been using TLS1.2 for the last 5 years without issue. – Panagiotis Kanavos May 26 '21 at 12:29
  • Well. What could be the solution then? Need to try something right? – Sreejith Krishnadas May 26 '21 at 12:36

1 Answers1

0

Try to load the certicate using the CreateFromPem static function, this method returns a new certificate with the private key.

var certificateCrt = File.ReadAllText("<Public Certificate>");
var privateKey = File.ReadAllText("<private key file>");
using var certificate = X509Certificate2.CreateFromPem(certificateCrt, privateKey);

If that doesn't work, try to creating a .pfx certificate using OpenSSL:

openssl pkcs12 -export -out certificate.pfx -inkey privateKey.key -in certificate.crt

I had this problem when I needed to use a certificate on a Windows OS, to work I had to create a .pfx certificate, but on other OS like Mac and Linux it worked fine without a .pfx certificate.

  • 1
    Hi Paulo, I tried this. Had to upgrade my projects to .Net 5. However it did not solve my problem. I tried intercepting with wireshark. When I try with postman I get to see the entire SSL handshake happening smoothly. However my app sends a TLS Alert : "Alert (Level: Fatal, Description: Protocol Version)" and then a RST, ACK. ALso on the windows event viewer I get this : "A fatal error occurred while creating a TLS client credential. The internal error state is 10013.". I am not sure what the issue is. Would you know anything about this? I am using WIndows 10. – Sreejith Krishnadas May 26 '21 at 11:54
  • Hi, did you try to use a simple HttpClient to make the request? `var bodyObject = new { }; using var httpClient = new HttpClient(handler); using var content = new StringContent(JsonSerializer.Serialize(bodyObject), Encoding.UTF8, "application/json"); var response = await httpClient.PostAsync("http://localhost:5000/api", content);` – Paulo Gomes May 26 '21 at 12:09
  • Yes. I stripped down everything. And tried with something pretty similar to what you have shared. Still no luck. With or without adding a certificate, I get the same error. System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> System.ComponentModel.Win32Exception (0x80090326): The message received was unexpected or badly formatted. – Sreejith Krishnadas May 26 '21 at 12:14
  • Also on the event viewer I get this : A fatal error occurred while creating a TLS client credential. The internal error state is 10013. – Sreejith Krishnadas May 26 '21 at 12:16
  • 1
    Have also tried what is mentioned in this post but that didint work either: https://mariusbancila.ro/blog/2019/04/08/enabling-tls-12-in-your-dotnet-framework-applications/ – Sreejith Krishnadas May 26 '21 at 12:20