Certificate based authentication with WCF has two components – configuring credentials and determining trust.
The first part is easy – you simply set the clientCredentialType in the binding’s security configuration to Certificate. This means that WCF will demand that the client sends a certificate along with the (first) request – either as a WS-Security X509 token or using SSL client certificates (depending on the security mode this also means that this requirement becomes part of the WSDL/Policy).
Furthermore the “plumbing” (either SSL or WCF message security) will make sure that the incoming certs are technically valid. This includes making sure that the certificate is not malformed and that the signature matches the public key. If this is not the case, the request gets rejected at a very low level and usually your service code would never get invoked.
At this point you have a technically valid certificate – but this does not necessarily mean that you also trust that certificate. The default validation strategy for certificates (regardless of message vs. transport) is called Chain Trust, this means:
- the certificate must be issued from a CA in your trusted CA list (in the machine certificate store)
- this intended purpose of that CA must include “Client Authentication”
- the current date/time must be within the certificate’s validitiy period
With message security you also get a mode called Peer Trust. In this mode WCF simply checks if the incoming certificate is installed in the Trusted People folder in the certificate store (the expiration time is checked too).
When to use which mode?
Since the Trusted People folder must hold all allowed certificates, this means that the service (or the client) has to know every peer a priori. This is OK if you have a limited amount of certificates that you want to allow – but does not scale very well. If you have more than one service on a machine and want to use peer trust, you have to run them under different accounts and use the current user certificate store to separate the “allowed” list.
Chain trust is for scenarios where you don’t know every certificate explicitly, but want to establish trust based on the issuer. The problem you have here is, that by default the trusted CA list is quite, errm, extensive. It includes popular CAs like VeriSign and not so popular ones (which I never heard before). So using chain trust it is quite easy to get a certificate that would be trusted by your service.
So in a lot of cases peer trust is not enough and chain trust is too much. What you typically want to have is first validating the trust chain and afterwards restrict to a specific CA or specific properties in the client cert. How do you accomplish that? Well – it depends ;)
In classic SSL transport security this is accomplished by using a Certificate Trust List (CTL). The moral equivalent in message based security is a X509 Certificate Validator. A third approach (which works in both modes) would be a WCF Service Authorization Manager.
In the next posts I will have a look at these technique and show you the up/downsides of each. Stay tuned.