Two way SSL – X509Certificate2.CreateFromPemFile – WINHTTP_CALLBACK_STATUS_REQUEST_ERROR

Total
1
Shares

I am trying to call an API which requires two way SSL (TLS 1.2) and I have the following code:

var myCert = X509Certificate2.CreateFromPemFile(_publicFilename, _privateFilename);

using (var handler = new WinHttpHandler())
{
    handler.ClientCertificateOption = ClientCertificateOption.Manual;
    handler.ServerCertificateValidationCallback = (x, y, z, w) => true;
    handler.ClientCertificates.Add(myCert);
    handler.SslProtocols = SslProtocols.Tls12;

    using (var client = new HttpClient(handler))
    {
        var postData = new StringContent("", UnicodeEncoding.UTF8, "application/json");
        var response = await client.PostAsync("<API Endpoint>", postData);

        string responseString = await response.Content.ReadAsStringAsync();
        Console.WriteLine(responseString);
    }
}

However, when I call that I get the following WinHttp exception:

Error 12185 calling WINHTTP_CALLBACK_STATUS_REQUEST_ERROR, ‘No
credentials were available in the client certificate.’.

Also in the windows event viewer I get the following error message:

The TLS client credential’s certificate does not have a private key
information property attached to it. This most often occurs when a
certificate is backed up incorrectly and then later restored. This
message can also indicate a certificate enrollment failure.

Unable to figure out what the issue is. I am using the exact same certificate and key in postman and it works fine.


Solution

TLS on Windows (WinHttpHandler, SslStream, or the default HTTP handler (which uses SslStream)) requires that the certificate have a named private key.

You can do that on a temporary basis by importing a PFX without PersistKeySet… but how do you get a PFX? Well, pretty easy.

var myCert = X509Certificate2.CreateFromPemFile(_publicFilename, _privateFilename);

using (var tmpCert = new X509Certificate2(myCert.Export(X509ContentType.Pfx)))
using (var handler = new WinHttpHandler())
{
    ...
    handler.ClientCertificates.Add(tmpCert);
    ...
}

The named key will be deleted when tmpCert gets Disposed. If you have complex or long life, you can create the cert not in a using statement. If the cert gets garbage collected and the process stays active long enough to run the finalizers the key will get cleaned up then.

Leave a Reply

Your email address will not be published. Required fields are marked *