HttpClient with client certificate loaded from file

4

I want to add mutual authentication to my client .NET application that is running under IIS server (it's a web service that calls another web service). Client app loads client certificate from file and it works fine with the following code on my development machine (I tried Windows 7 and Windows 10 with .NET 4.6.2):

var handler = new WebRequestHandler();
var certificate = new X509Certificate2(clientCertPath); -- PFX file with client cert and private key 
handler.ClientCertificates.Add(certificate);
handler.AuthenticationLevel = AuthenticationLevel.MutualAuthRequired;
client = new HttpClient(handler);

But when this code is deployed to production Windows 2016 Server machine the application throws The request was aborted: Could not create SSL/TLS secure channel.

I enabled tracing for System.Net this is what I see in logs

SecureChannel#66407304 - Certificate is of type X509Certificate2 and contains the private key.
AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
AcquireCredentialsHandle() failed with error 0X8009030D.
AcquireCredentialsHandle(package = Microsoft Unified Security Protocol Provider, intent  = Outbound, scc     = System.Net.SecureCredential)
AcquireCredentialsHandle() failed with error 0X8009030D.
Exception in HttpWebRequest#60537518:: - The request was aborted: Could not create SSL/TLS secure channel..

As it turned out this error is caused due to the lack of IIS user's permissions to read private key in PFX file. So when I import it into machine certificate store and add IIS_IUSRS by clicking right-button on client certificate All Tasks -> Manage Private Keys... everything works fine, but I want to avoid that.

Is there a way to work with client certificate loaded from file on Windows Server and don't import client certificate PFX file into certificate store?

c#
iis
dotnet-httpclient
client-certificates
mutual-authentication
asked on Stack Overflow May 31, 2017 by klappvisor • edited May 31, 2017 by klappvisor

3 Answers

1

First, try X509KeyStorageFlags.PersistKeySet. Next as I understand you can just use the key with importing it into key storage. As described here you should first of all import key into the store (whether persistent or not) and then use the key.

answered on Stack Overflow May 31, 2017 by Oleg M • edited May 31, 2017 by Oleg M
0

Since the example where things work involve using the machine store, you can try changing to a MachineKeySet load.

Replace

var certificate = new X509Certificate2(clientCertPath);

with

var certificate = new X509Certificate2(clientCertPath, null, X509KeyStorageFlags.MachineKeySet);

This shouldn't be necessary for client authentication certificates, but if you have user impersonation happening between load and use that can cause user keyset problems.

answered on Stack Overflow May 31, 2017 by bartonjs
0

Try this, just add this in the startup code

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

        ServicePointManager.ServerCertificateValidationCallback =
            (a, b, c, d) => true;
answered on Stack Overflow Nov 19, 2019 by Kaptein Babbalas

User contributions licensed under CC BY-SA 3.0