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:
- When using the client
pfxfile contains the private key, the client is able to communicate to the server in the mtls fashion. - When using the client
pfxfile 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)
- In neither case, the provided
CustomX509AsymmetricSecurityKeyas per the how-to above was NOT used by theWCFframework. Did not even instantiate the class. TheCustomX509SecurityTokenwas instantiated via theCustomX509SecurityTokenProvider. But theSecurityKeysproperty of theCustomX509SecurityTokenclass was never called, which is where the custom private key comes to play.
Questions
- Is the how-to guide out of date? Notice it is dated
03/30/2017. - The exception when using the
pfxwithout private key is sort of self-explanatory. I did not provide the private key. Why didn't WCF use the providedCustomX509AsymmetricSecurityKeyas the private key? Isnt this the whole point that the user is providing an alternative private key in the form of aX509AsymmetricSecurityKey? - Am I following the wrong guide to achieve what I want? I did try to set the
PrivateKeyproperty of theX509Certificate2class with a customRSAimplementation. But got lost trying to implement theICspAsymmetricAlgorithminterface which is required by theX509Certificate2.PrivateKey