1

I am working to integrate with a third-party that provides sample code for use with cURL. I've been able to successfully connect using cURL via the following command:

curl -k -d "grant_type=client_cert" --basic -u "myUserName:myPassword" -H "Content-Type: application/x-www-form-urlencoded" --cert c:\certs\myCert.pem https://vendorUrl/method

In reading the cURL docs, I believe this is what all the switches translate to:

  • -k: insecure (proceed even if connection is not secure)
  • -d: data. Also indicates this is a POST.
  • --basic: basic auth
  • -u username/password
  • -H additional header
  • --cert: pass certificate

I have tried many (!) different tips I've found online, so there are some lines of code that may be unnecessary. I have tried to indicate where I have interpreted cURL switches to C# in my code comments.

        //Not sure if these are needed or not.
        ServicePointManager.Expect100Continue = true;
        ServicePointManager.CheckCertificateRevocationList = false;

        //allow every possible protocol for now just to eliminate the protocol as the source of the problem
        ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;

        //this should be the equivalent of cURL's "-k" (insecure) switch.
        ServicePointManager.ServerCertificateValidationCallback += (sender, certificate, chain, sslPolicyErrors) => true;

        var certificatePath = ConfigurationManager.AppSettings.GetValue("myPath");
        var clientKey = "myKey";
        var clientSecret = "mySecret";

        var url = "https://vendorUrl/method";

        //create the request
        var request = new RestRequest(Method.POST);

        ////this should be the equivalent of cURL's -d (data) switch.  no idea if this is done correctly.  I have also tried adding this as "AddJsonBody()"
        var body = "grant_type=client_cert";
        request.AddBody(body);

        //this should be the equivalent of cURL's "-H" (header) switch
        request.AddHeader("Content-Type", "application/x-www-form-urlencoded");

        //Import certificate
        var certificates = new X509Certificate();
        certificates.Import(certificatePath);

        var client = new RestClient
        {
            BaseUrl = new Uri(url),
            //this should be the equivalent of cURL's "--cert" switch
            ClientCertificates = new X509CertificateCollection { certificates },
            //this should be the equivalent of cURL's "--basic" (Basic Auth) switch and the "-u" switch
            Authenticator = new HttpBasicAuthenticator(clientKey, clientSecret)
        };

        var response = client.Execute(request);

The error message I get is the dreaded "The request was aborted: Could not create SSL/TLS secure channel."

I also added trace logging as described here: The request was aborted: Could not create SSL/TLS secure channel.

I don't really know how to parse the output of the trace, but one of the last messages in the trace looks like a problem:

System.Net Information: 0 : [9232] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=IllegalMessage).

Phil Sandler
  • 27,544
  • 21
  • 86
  • 147
  • RestSharp doesn't do anything to support SSL, both self-signed or real ones. We just create a `WebRequest`. So if you can manage to get it working with `WebRequest` - it will work with RestSharp... I know that this is not very helpful but still. – Alexey Zimarev Dec 06 '17 at 13:16

1 Answers1

0

In my case, I had to install the certificate on the local computer/server in order to get this to work. It's not clear to me why cURL works without the certificate installed.

The certificate I had to install had a .p12 extension. So in code I loaded the .pem file, which is a file derived from the .p12 file. I'm not claiming to understand why.

By switching to HttpClient, I was able to avoid loading the .pem file by adding:

            var handler = new WebRequestHandler();
            handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
            var httpClient = new HttpClient(handler);

I was not able to find a RestSharp/WebRequest equivalent to ClientCertificateOptions.

Phil Sandler
  • 27,544
  • 21
  • 86
  • 147