This post covers the steps required to secure communication between a WCF client and a WCF data service using mutual certificate authentication.
The client/service topology is depicted below:
Both the client and server run on a Windows Server 2008 R2 virtual machine with Windows SDK 7.1, Visual Studio 2010, SQL Server Express 2008 R2 and .NET framework 4.0.
A detailed discussion of public key cryptography is outside the scope of this article. However, I highly recommend that you read more here to get a better understanding of the underlying principles, so that you can better understand the ‘How-To’ steps that follow.
In essence the client possesses a public key certificate (hereafter known as a client certificate) with associated private key. Similarly, the service has possession of another public key certificate (hereafter known as a service certificate) with associated private key. For a given pair of keys, either the public or private key can be used to encrypt data but ONLY the corresponding key can decrypt the data. The public key is available to the world at large but the private key MUST remain with the owner alone. In this way the owner is able to encrypt data using the private key and a party in receipt of encrypted data can decrypt it using the public key. The fact that the receiving party can successfully decrypt the data using the public key means that the data MUST have been encrypted by the corresponding private key and, as only the owner has access to the private key, the data MUST have originated from the owner; this is known as nonrepudiation as the owner cannot claim that encrypted data did not originate from them (of course, the private key may have been stolen but that is a different matter).
Translating this to the current scenario, in order for the client and service to successfully converse using certificates, the WCF client application must have access to the client’s private key and IIS (the receiving party) must have access to the client’s public key. Conversely, IIS must have access to the service private key and the client must have access to the service public key.
In an Active Directory domain, the public key certificate is ordinarily assigned to a domain account such that IIS can locate the certificate using Active Directory Domain Services (ADDS). However, ADDS does not exist in a workgroup environment and so the client certificate public key list must be maintained within IIS itself.
The certificates in this article are issued by a certificate authority, in this case a trusted root certificate created using the makecert tool that ships with the Windows SDK.
The client application, as owner of the client certificate, needs access to the private key at runtime. We are going to create an interactive client (e.g. – Console, WinForm, Silverlight, Internet Explorer etc.), and so the certificate will be installed in the Current User – Personal store. If the client was non-interactive (e.g. – NT service) the certificate would be installed in the Local Machine – Personal store.
Additionally, as the client certificate has been issued from a trusted certificate authority (CA), the root certificate created in 1) must also be installed.
The service, as owner of a service certificate, needs access to the private key at runtime. As the service is non-interactive (i.e. – it is not running under the context of a logged-on user), the certificate will be installed in the Local Machine – Personal store.
Additionally, as the service certificate has been issued from a trusted certificate authority (CA), the root certificate for the CA must also be installed so that the chain of trust can be verified.
IIS needs access to the client’s public key certificate. In this section the certificate is exported for later use.
The WCF client needs access to the service public key certificate. In this section the certificate is exported for later use.
In this section a basic WCF data service is created in order to secure it using mutual authentication.
In order to make life a little easier, we will create and configure the WCF client before locking down the service.
Both IIS and the WCF data service must be configured for client certificate authentication, otherwise there is a mismatch and a service activation failure similar to ‘The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'Ssl'’ will occur.
In this section the public key certificate from 4) is registered with the data service website.
Client certificates can be mapped in a ‘one to one’ or ‘many to one’ relationship with Windows accounts. ‘one to one’ means that a client certificate is linked to a single Windows account. ‘many to one’ means that many client certificates are assigned to a single Windows account.
In this post we will use the ‘one to one’ relationship but the ‘many to one’ relationship does not differ greatly
The data service must also be configured to mandate client certificate authentication.
In web.config, overwrite the <system.serviceModel> element with the following
The contents of the <webHttpBinding> element mandate that client certificate authentication at the transport level is required for the binding. The <services>/<service>/<endpoint> element describes the contract that all WCF data services must adhere to.
As this article is concerned with mutual authentication then it is not sufficient for only the service to authenticate the client. In addition, the client must be certain that it is calling the right endpoint. One way to achieve this is to store the service public key certificate with the client so that during runtime, the SSL certificate presented by the service can be compared against the locally stored version. In this way the client can be sure that it is calling the correct SSL endpoint located at www.mydataservice.com and that it has not been phished into calling another endpoint with the same URL but different SSL certificate.
As the service is now locked down, the client will not be able to use it without undergoing some modification.
Note that the ClientCertificate property of the proxy is not recognised; this represents the last piece of the puzzle. As there is no declarative configuration for the WCF client (i.e. - no <system.serviceModel> element was created in the client config file, unlike for, say, a standard SOAP based web service), the client certificate is hooked in programmatically by intercepting the underlying HttpWebRequest instance.
Overwrite Reference.cs contained within the MyDataServiceEntities service reference, with the following
In this article I have demonstrated a methodology for securing communication between a WCF client and a IIS hosted WCF data service, installed on a workgroup server, using mutual certificate authentication. While in many ways similar to mutual authentication scenarios described elsewhere, securing a WCF data service exhibits some unique characteristics that warranted documenting.
I hope you find this useful.
Written by [BradleyCotier]