Sunday, January 3, 2010

WCF Client Authentication using X509 certificates on SSL

In one of my project; there is a requirement

a. Web Services (WCF) Clients should be authenticated by X509 certificates.

b. Clients should validate the web services using X509 certificate (using SSL).

c. All these services should be built using basicHttpBinding and to be consumed by .Net 2.0 clients.

I am describing here the complete solution to achieve this and the settings to be done in IIS.

SSL Layer: In order to run web services on SSL; you need to get certificate from the certificate authority like VeriSign; however in development environment sometimes you donot have certificate from valid Authority and need to generate self signed certificate. Microsoft provides a utility to generate self signed certificates.

makecert.exe -r -pe -a sha1 -n CN=”Ent.com” -sr LocalMachine -ss My -sky exchange -b 01/01/2000 -e 01/01/2036 Ent.cer

The above command creates the self signed certificates and places this certificate in the Local Computer Account under personal store.

The configuration in IIS is simple as shown below:

a. Right Click WebSite (say Ent.com, where your WCF services are hosted). Go to properties and then go to Directory Security tab.


b. Click Server Certificate button. This will open the wizard to install certificate. Click “Next” and you will see the following screen. Select option “Assign an existing certificate” and click “Next”.

c. Now select the certificate you created “Ent.com” and click “Next”.


  1. Select the port number (for SSL default is 443) and click finish.
  2. Now if you want to enable 128 bit encryption you can edit the certificate details by clicking “Edit” button on the Directory Security tab and click the checkbox “Require 128-bit encryption”.


Some configuration changes need to be done in web.config file (WCF hosting configuration file). These configuration settings are described at the end of article.


That’ it you are done with installing SSL.

Now you can Add Web Reference in your .Net 2.0 project. However when you try to access the Web Service from your client application you will get the following error:


“The underlying connection was closed: Could not establish trust relationship for the
SSL/TLS secure channel.”


This exception is raised by client during SSL handshake because Server certificate is not issued b
y valid Authority.

In order to fix this problem, you need to tell client that it allows your certificate. The following code needs to be written and called before calling the service method.

protected void button1_Click(object sender, EventArgs e)

{

Testing.Service service1 = new Testing.Service();

ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(customCertificateValidation);

string data = service1.GetData(5, true);

label1.Text = data;

}

private bool customCertificateValidation(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)

{

//analyze the certificate and then return true.

return true;

}

The custom certificate validation method allows clients applications to decide which server certificates they can trust.

Note: Allowing self signed certificates is not recommended in Production environment.



X509 Client Certificate Authentication:

The next thing to do is client authentication using X509 certificates. In order to do this you need to change configuration in IIS and also in web.config file.

IIS settings

a. Right Click web site (say Ent.com). Go to properties and then go to Directory Security tab.


b. Click Edit button and then on “Client Certificate” Section select the option “Require client certificates”


Client Side Changes

Now when you call the web service you need to provide client Certificate. Here is the code:

protected void button1_Click(object sender, EventArgs e)

{

Testing.Service service1 = new Testing.Service();

//As an example loading certificate from file system.

X509Certificate cert = X509Certificate2.CreateFromCertFile(@"C:\Test1.cer");

service1.ClientCertificates.Add(cert); //adding cleint certificate.

ServicePointManager.ServerCertificateValidationCallback += new System.Net.Security.RemoteCertificateValidationCallback(customXertificateValidation);

string data = service1.GetData(5, true);

label1.Text = data;

}

private bool customXertificateValidation(object sender, X509Certificate cert, X509Chain chain, System.Net.Security.SslPolicyErrors error)

{

//analyze the certificate and then return true.

return true;

}

The “Test1” certificate used here is self signed certificate. In production environment this certificate should be issued by valid authority. However to fix the problem in development environment you need to add the certificate in the “Trusted Root Certification Authorities” on you WCF hosting machine.


Web.config changes:

The complete config file is:

<system.serviceModel>

<services>

<service name="Service" behaviorConfiguration="ServiceBehavior">

<endpoint address="https://Ent.com/Services/Service.svc" binding="basicHttpBinding" contract="IService" bindingConfiguration="Binding">

<identity>

<dns value="localhost"/>

identity>

endpoint>

service>

services>

<behaviors>

<serviceBehaviors>

<behavior name="ServiceBehavior">

<serviceMetadata httpsGetEnabled="true"/>

<serviceDebug includeExceptionDetailInFaults="true"/>

behavior>

serviceBehaviors>

behaviors>

<bindings>

<basicHttpBinding>

<binding name="Binding">

<security mode="Transport">

<transport clientCredentialType="Certificate"/>

security>

binding>

basicHttpBinding>

bindings>

system.serviceModel>


Description:

  • In order to use SSL you need to tell that you are using transport layer security using the tag.

<security mode="Transport">security>

  • In order to use client certificates for authentication you need to specify ClientCertificateType as Certificate

    <security mode="Transport">
    <transport clientCredentialType="Certificate"/>

    <security/>

However after changes these settings when you try to run the application you will get strange error saying:

Client found response content type of '', but expected 'text/xml'.
The request failed with an empty response.

In order to fix this error you need to comment the following line in web.config file

< ! - - < address="mex" binding="mexHttpsBinding" contract="IMetadataExchange">- - >

That’s all. Now you can use WCF services from .Net 2.0 clients on SSL and using client certificate authentication.


The complete Code can be downloaded from here

You can generate the certificate using Microsoft tool as described above.


Ashwani Kumar

Solutions Architect

Globallogic Inc.

No comments:

Post a Comment