WCF How to change the Cryptographic Provider for an X.509 Certificate's Private Key

Viewed 170

I am trying to extend WCF by following this how-to guide from microsoft. The basic idea is to use a hardware security module as the client-side private key holder, which means all cryptographic operations involving the client's private key must be carried out by the security module chip.

Setup

dotnet framework: 4.7.2
binding: netTcp
binding security: Message
clientCredentialType: Certificate (X509Certificate2) 
serverCertificate: X509Certificate2 

All certificates ( 1 server cert and 2 client certs ) are signed off by the same CA. The server certificate is a normal pfx file that contains both the certificate and private key. I prepared two different client certificates one with the private key and one without the private key. (two client side pfx files have the identical certificate )

Observations:

  1. When using the client pfx file contains the private key, the client is able to communicate to the server in the mtls fashion.
  2. When using the client pfx file without the private key, the attempt to set up secure session fails with the following exception
System.ArgumentException, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
The certificate '<cert name>' must have a private key. The process must have access rights for the private key.

Stack Trace

System.ServiceModel.Security.TlsSspiNegotiation.ValidatePrivateKey(X509Certificate2 certificate)
System.ServiceModel.Security.TlsSspiNegotiation..ctor(String destination, Boolean isServer, SchProtocols protocolFlags, X509Certificate2 serverCertificate, X509Certificate2 clientCertificate, Boolean clientCertRequired)
System.ServiceModel.Security.TlsnegoTokenProvider.CreateTlsSspiState(X509SecurityToken token)
System.ServiceModel.Security.TlsnegoTokenProvider.CreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout)
System.ServiceModel.Security.IssuanceTokenProviderBase`1.DoNegotiation(TimeSpan timeout)
  1. In neither case, the provided CustomX509AsymmetricSecurityKey as per the how-to above was NOT used by the WCF framework. Did not even instantiate the class. The CustomX509SecurityToken was instantiated via the CustomX509SecurityTokenProvider. But the SecurityKeys property of the CustomX509SecurityToken class was never called, which is where the custom private key comes to play.

Questions

  1. Is the how-to guide out of date? Notice it is dated 03/30/2017.
  2. The exception when using the pfx without private key is sort of self-explanatory. I did not provide the private key. Why didn't WCF use the provided CustomX509AsymmetricSecurityKey as the private key? Isnt this the whole point that the user is providing an alternative private key in the form of a X509AsymmetricSecurityKey?
  3. Am I following the wrong guide to achieve what I want? I did try to set the PrivateKey property of the X509Certificate2 class with a custom RSA implementation. But got lost trying to implement the ICspAsymmetricAlgorithm interface which is required by the X509Certificate2.PrivateKey
0 Answers
Related