2

This is my very first post. Firstly, I would like to thank everybody for all the contribution you have made to this site, as this made my work as a junior dev so much easier!

I have a problem with server handshake using RestSharp. I am adding certificate to RestSharp POST request, but it seems not to validate it properly. However exactly same post request with certificate added to Postman or running same code via Fiddler as a proxy seems to work fine.

I receive error: Error: System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.

I am completely lost. I replaced information I did not want to share with xxxxxxxxxx.

            ServicePointManager.DefaultConnectionLimit = 9999;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            ServicePointManager.ServerCertificateValidationCallback +=
               (sender, certificate, chain, sslPolicyErrors) => true;

            var client = new RestClient("xxxxxxxxxxxxxxxxxxx");


            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection collection = store.Certificates.Find(X509FindType.FindBySubjectName, "xxxxxxxxx", true);

            client.ClientCertificates = new X509CertificateCollection();
            client.ClientCertificates.AddRange(collection);
            client.RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true;


            var request = new RestRequest(Method.POST);
            request.AddHeader("X-IBM-Client-Id", "xxxxxxxxxxxxxxx");
            request.AddHeader("X-IBM-Client-Secret", "xxxxxxxxxxxxxxxxxxxxxxxx");
            request.AddHeader("Accept", "*/*");
            request.AddHeader("Content-Type", "application/json");

            var jsonToSend = JsonConvert.SerializeObject(requestBody);
            request.AddParameter("application/json; charset=utf-8", jsonToSend, ParameterType.RequestBody);
            request.RequestFormat = DataFormat.Json;


            SecurityShower.ShowRestSharpRequest(client, request);

            IRestResponse response = client.Execute(request);


            return String.IsNullOrEmpty(response.Content) ? response.ErrorMessage : response.Content;

I run Wireshark and found out that during handshake client (us) sends certfifcate lenght 0, so I take certificate is not included despite you can clearly see I added cert to RestSharp client. And it shows when I debug.

Please have a look at Wireshark snapshots:

wireshark snapshot 1

wireshark snapshot 2

I think it all comes down to how the Fiddler and Postman handle their handshake and cert. But it is still a mystery (or misery for that matter!) to me why .Net handles the process differently to those apps!

EDIT: Additional info.

I have added this code:

ServicePointManager.ServerCertificateValidationCallback += new RemoteCertificateValidationCallback(ValidateServerCertificate);

(...)

  public static bool ValidateServerCertificate(
            object sender,
            X509Certificate certificate,
            X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
        {

            Console.WriteLine("Validation of server cert.");
                return true;

}

And I discovered that this piece of code is not executed.

Anyway - I am not sure how to go deeper into abstraction using .net, I do not know how to programmatically influance handshake procedure... or if it is even possible in .net... :(

ms81
  • 31
  • 6
  • HTTP uses TCP as the transport layer. The SSL/TLS is the methods for making the http connection secure using TCP. Your code is failing the TCP security. Code Project has a number of good sample of SSL/TLS. First make sure your browser settings are set to use TLS 1.2 Also I've seen a number of issues recently with certificates using 32 and 64 bit encryption modes. You may want to try setting project to 64 bit mode (or 32 bit mode) to see if it solves issues. Win 10 seems to automatically use 64 bit mode which doesn't work with a 32 bit certificate. – jdweng Oct 24 '19 at 10:29
  • There are lots of options with certificates (see wiki : https://en.wikipedia.org/wiki/Transport_Layer_Security). It looks like your code is using TLS 1.2 which is using a 256 bit key. I believe setting project to x64 mode may be defaulting to TLS 1.3 which may not work with the 1.2 certificate. Not sure. – jdweng Oct 24 '19 at 10:42
  • Thank you for your answer, I run it in both x86 and x64 modes - same result. – ms81 Oct 24 '19 at 13:07
  • Are the headers the same as Postman? – jdweng Oct 24 '19 at 14:03
  • yes, exactly the same as in Postman. Also when I use Fiddler as proxy (I added cert to Fiddler) - it also works. – ms81 Oct 24 '19 at 14:10
  • Does code find certificate in the Store (does not return null)? Do you see the TCP connection being made in Wireshark? – jdweng Oct 24 '19 at 16:12
  • Yes, connection is established, I send Client Hello, Receive Server Halo, Server Cert and Server Key Exchange. Then Handshake fails after I send Certificate with Lenght 0 (as on the photos). In the code, while debugging, I see certificate is found in store and attached to client (not null), I start to think I am getting mad! – ms81 Oct 24 '19 at 17:08
  • Check to see if you are getting errors (https://learn.microsoft.com/en-us/dotnet/api/system.net.security.remotecertificatevalidationcallback?view=netframework-4.8). Maybe the SecurityProtocolType.Tls12 is not correct. – jdweng Oct 24 '19 at 17:18
  • Then you are closing connection. You should see a [FIN] in the sniffer data on the TCP. – jdweng Oct 25 '19 at 07:20
  • I think it may be a duplicate of [Add certificate on request with RestSharp](https://stackoverflow.com/questions/49069197/add-certificate-on-request-with-restsharp) – Atta H. Oct 28 '19 at 14:04
  • @AttaH. It is not a duplicate, I wish it was as that one is solved! – ms81 Oct 28 '19 at 14:51
  • I use the similar code and it worked for me. Only difference is i created custom class for serialization and the calling the service – Atta H. Nov 01 '19 at 15:57

1 Answers1

1

After the response from server side people we found out my program was written correctly. The issue (apart from poor communication from API provider!) was our certificate which the server was unable to consume. I was sending self-signed cert to the server running some old version of Windows Server. I was told the certificate I have been using is correct, however the Server, during handshake, was sending Trusted Certificate List which my cert could not match so my .Net written program was sending certificate length 0. Which is consistent with TLS 1.2 protocol. After uploading certificate chain that included certificate that matched one of authorities from trusted certificate list provided by server connection was established and all works as intended.

Thank you for all the answers and happy coding!

ms81
  • 31
  • 6