I am unable to get the HttpClient class to send a client certificate using .NET Core on Windows.
Here is the code I am using:
X509Certificate2 certificate = new X509Certificate2(@"C:\Repos\selly\client1.pfx", "password");
HttpClientHandler handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ServerCertificateCustomValidationCallback = (a,b,c,d) => { return true; };
handler.ClientCertificates.Add(certificate);
HttpClient client = new HttpClient(handler);
var content = new StringContent("");
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
client.PostAsync("https://client2:5002/api/values", content).Wait();
The code works as expected on Linux (Ubuntu 16.04) (obviously, with the path to the certificate changed). It does not work on Windows.
Looking at the exchange in Wireshark, the client does not send the certificate when running on Windows (10 v1703).
I have run similar code using .NET Framework (using 'WebRequestHandler' instead of 'HttpClientHandler'). It correctly sends the client certificate.
I found the following online, but unlike the problem described there, the server certificate callback is executed. I did generate the certificates myself, but they are all signed by a Root CA, (which is installed on both client and server) and all the details are correct.
I also found this, which suggests that client certificates do work with HttpClient on .NET Core on Windows.
I have also tried explicitly setting the TLS version, however the problem persists.
I am using Kestrel as the web server. It is configured as follows:
.UseKestrel(options =>
{
var sslOps = new HttpsConnectionFilterOptions();
sslOps.ClientCertificateMode = ClientCertificateMode.RequireCertificate;
sslOps.ClientCertificateValidation = CheckClientCertificateLogic.CheckClientCertificate;
sslOps.ServerCertificate = new X509Certificate2(@"C:\Repos\selly\client2.pfx", "password");
options.UseHttps(sslOps);
})
The 'ClientCertificateValidation' callback does not execute on requests received from a Windows client; probably because it hasn't received a certificate for it to check...
Is this a bug in .NET Core? Is there a workaround?