Spodgy
Spodgy

Reputation: 322

HttpClient POST request with Client Certificate

I'm trying to make a call to a third-party API which requires a client certificate. I generated the client certificate using the SSL tool and uploaded this to the third party site. I have generated a successful POST request through Postman, providing the client certificate through their dialogs.

The Headers are:

Body (x-www-form-urlencoded)

When I perform a similar request through .NET I am receiving an error code indicating the certificate is not present. I have added the certificate to my personal certificate store and verified the certificate has been added to the webhandler through debugging. Can anyone suggest what the error might be or how I could diagnose the issue?

    static async void LaunchRawHttpClient()
            {
                System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12 | System.Net.SecurityProtocolType.Tls11 | System.Net.SecurityProtocolType.Tls;
                ServicePointManager.ServerCertificateValidationCallback +=
                    ValidateServerCertificate;


                string page = "https://<URL>";

                var handler = new WebRequestHandler();
                X509Certificate2 cert = GetMyCert();
                if (cert!=  null)
                {
                    handler.ClientCertificates.Add(cert);
                }
                else
                {
                    Console.WriteLine("Cert not found");
                    Console.ReadLine();
                    return;
                }


                // ... Use HttpClient.
                using (HttpClient client = new HttpClient(handler))
                {
                    client.DefaultRequestHeaders.Add("X-Application", "<applicationname>");
                    client.DefaultRequestHeaders.Add("Accept", "application/json");

                    var nvc = new List<KeyValuePair<string, string>>();
                    nvc.Add(new KeyValuePair<string, string>("username", "<username>"));
                    nvc.Add(new KeyValuePair<string, string>("password", "<password>"));

                    FormUrlEncodedContent reqContent = new FormUrlEncodedContent(nvc);
                    reqContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded");


                    using (HttpResponseMessage response = await client.PostAsync(page, reqContent))
                    using (HttpContent content = response.Content)
                    {
                        // ... Read the string.
                        string result = await content.ReadAsStringAsync();

                        // ... Display the result.
                        if (result != null)
                        {
                            Console.WriteLine(result);
                        }
                    }
                }
            }

static X509Certificate2 GetMyCert()
        {
            string certThumbprint = "<thumbprint>";
            X509Certificate2 cert = null;

            var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            store.Open(OpenFlags.ReadOnly);
            X509Certificate2Collection certCollection = store.Certificates.Find
                (X509FindType.FindByThumbprint, certThumbprint, false);

            if (certCollection.Count > 0)
                cert = certCollection[0];

            store.Close();

            return cert;
        }
public static bool ValidateServerCertificate(
            object sender,
            X509Certificate certificate,
            X509Chain chain,
            SslPolicyErrors sslPolicyErrors)
        {
            if (sslPolicyErrors == SslPolicyErrors.None)
            {
                Console.WriteLine("No SSL Errors");
                return true;
            }

            Console.WriteLine("Certificate error: {0}", sslPolicyErrors);
            Console.ReadLine();
            return false;
        }

I receive "No SSL Errors" message x2, followed by the missing certificate status code.

Thanks in advance Jim

Upvotes: 1

Views: 3088

Answers (1)

Spodgy
Spodgy

Reputation: 322

Finally found the answer on this - the problem was the private key file was not being loaded. Postman sent requests successfully, as did Curl. Curl asks for the key file explicity and this was a clue.

In .NET Core - there's a function on the X509Certificate2 object which allows you to copy it to another object combined with the key file. My project is in .NET framework and Core wasn't available.

The option I went for was using openssl to combine the cer and the key file into a pfx, which I loaded into the X509Certificate2 object. The Http Post then succeeded.

Upvotes: 1

Related Questions