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
pfx
file contains the private key, the client is able to communicate to the server in the mtls fashion. - 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)
- In neither case, the provided
CustomX509AsymmetricSecurityKey
as per the how-to above was NOT used by theWCF
framework. Did not even instantiate the class. TheCustomX509SecurityToken
was instantiated via theCustomX509SecurityTokenProvider
. But theSecurityKeys
property of theCustomX509SecurityToken
class 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
pfx
without private key is sort of self-explanatory. I did not provide the private key. Why didn't WCF use the providedCustomX509AsymmetricSecurityKey
as 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
PrivateKey
property of theX509Certificate2
class with a customRSA
implementation. But got lost trying to implement theICspAsymmetricAlgorithm
interface which is required by theX509Certificate2.PrivateKey