5

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?

klappvisor
  • 1,099
  • 1
  • 10
  • 28
  • where is your client running and what kind of application is the client ? is the client running inside IIS worker process ? And Where is it throwing the error ? Client side or server side ? – Rohith May 31 '17 at 09:34
  • it's .NET web application that does HTTP call to remote server using client mutual authentication. it is running inside IIS worker process. Error is on client side – klappvisor May 31 '17 at 09:42
  • Does it work when you import into the user cert store, or are you using the machine cert store? – bartonjs May 31 '17 at 13:02
  • I import it to machine store since it's should be accessed by different user, and yes, it works when I import it and add `IIS_IUSRS` to `All Tasks -> Manage Private Keys...` I will edit question... – klappvisor May 31 '17 at 13:39
  • 1
    I had the same issue when loading a pfx file under IIS. Turns out I needed to edit the application pool and then enable Load User profile as detailed here https://stackoverflow.com/questions/2609859/how-to-give-asp-net-access-to-a-private-key-in-a-certificate-in-the-certificate/47506891#47506891 – Chris Stubbs Aug 17 '23 at 15:29

3 Answers3

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.

Oleg M
  • 265
  • 4
  • 13
  • I tried but unfortunately it did not work. I do want to avoid importing keys into the store and work with pfx file as it works on desktop Windows – klappvisor May 31 '17 at 13:46
  • What about IIS Application Pool Identity? Did you try to change the default ApplicationPoolIdentity to some user with higher privileges? – Oleg M May 31 '17 at 14:09
1

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.

bartonjs
  • 30,352
  • 2
  • 71
  • 111
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;
Kaptein Babbalas
  • 1,058
  • 12
  • 15