WCF transport security and client certificate authentication with self-signed certificates

I have only recently got into contact with Windows Communication Foundation (WCF). As a newbie, one of the things I struggled with at first was securing a WCF service with self-signed certificates. Never having used certificates and not knowing how it actually works, it was challenging task to say the least. Looking back now it makes me feel a little silly …

For this post we will use a common business-2-business scenario. We will create a transport-secured (HTTPS) WCF service with certificate client-credential authentication.

1. Create the solution setup:

For this scenario, we will build a solution called “WCF.Tutorial.TransportSecurity”

Solution overview

There are 2 projects in this solution: (both are default template projects)

  1. WCF Service Application called “WCF.Tutorial.TransportSecurity.Service” 
  2. Client console application called “WCF.Tutorial.TransportSecurity.Client”

For the WCF Service Application I removed the default service and the contract and added a WCF Service called “EmployeeService”, which is linked to the IEmployeeService contract.
The service contract looks as following:
Service contract
The service implementation:
Service implementation
Basically we created a WCF service application with a service called “EmployeeService”, which has 1 very simple operation for testing purposes.

2. Configuration of the Service

Next step is to set the configuration of the WCF service EmployeeService. This can be done by code, by configuration or by a mix of both. For ease of understanding, we will do all by configuration throughout this tutorial.
The web.config should look like this by default:
Default web.config
We will remove all content in the <system.serviceModel> node
System.ServiceModel
We add all configuration we need for a Transport-secured WCF Service with client certificate authentication.
1. Add the EmployeeService service configuration:
WCF Service configuration
The service name contains the full namespace and the name of the service we created, which in our case is EmployeeService
The endpoint has an empty address and that is because we will host the WCF service in IIS, which means an address is not required for the service if you host it in IIS. We use a default basicHttpBinding and the contract points to the Service contract interface. Note the full namespace is included in the endpoint contract.
2. Add the EmployeeService binding configuration
basicHttpBinding binding configuration
We add a basicHttpBinding configuration (Note our service endpoint uses a basicHttpBinding, so in this case we configure a basicHttpBinding for our service). We call the binding configuration “EmployeeBindingConfig”
The security mode for this basicHttpBinding is set to “Transport”. As we set the security mode to transport, we need to configure the <transport> node within the <security> node.
On the transport node we set clientCredentialType to “Certificate” .
This means we configured a basicHttpBinding that will use Transport security (HTTPS) and that the client has to authenticate by a certificate.
IMPORTANT: Notice that the Employee service endpoint configuration has bindingConfiguration set to “EmployeeBindingConfig”. This bindingname matches the binding we just configured in the image above. This means the service endpoint will use the basicHttpBinding configuration we defined above.
3. Add the EmployeeService behavior configuration
WCF transport security behavior configuration
We will add a behavior to our configuration, which defines the behavior of our EmployeeService. Our behaviour is called “EmployeeServiceBehavior”. Please note that our EmployeeService service configuration is also set to a behaviorConfiguration of “EmployeeServiceBehavior”, which matches the behavior we created.
Service ClientCertificate behavior
This is import to make sure you set the behavior configuration of your service to the one you create.
The behavior we created sets some authentication settings for the clientCertificate (which is used for authentication of the client).
At this time the settings might not make any sense. For you to understand we will need to make our hands a little dirty and dig a bit deeper into certificate authentication, which we will in a few. For the time being you can ignore these settings as I will come back to them later.

3. IIS configuration for the service and Transport security certificate configuration

As mentioned before, we will host our WCF service in IIS web server, which is an ideal host and preferred anytime over any managed host, unless it is not possible of using IIS/WAS. I will not handle all features and possibilities of hosting WCF services or Internet Information Services, but for this completion of this service, I will add some run-through of how I hosted my service quickly into IIS for development purposes.
Go to Properties of the “WCF.Tutorial.TransportSecurity.Service” project and go to the tab “Web”. It should look as following:
Upload WCF Service to IIS Express
By default the Cassini development server will be used by “Use Visual Studio Development Server”. Change this to “Use Local IIS Web Server”. Press the “Create Virtual Directory” button. It will create a virtual directory in your IIS under the Default website for you, saving you of the hassle of creating your application yourself.
Open IIS (Run – enter “inetmgr” and press enter. The IIS console should open). It should look as following:
IIS WCF Service application
You should be able to visit the service at the following url:
http://localhost/WCF.Tutorial.TransportSecurity.Service/EmployeeService.svc
When you visit our service by web browser, you will most likely get the following error:
IIS HTTPS binding error
No https scheme could be found for the binding. If you get this error, this means there is no HTTPS binding defined yet for the “Default website”, under which our application is.
Configure IIS HTTPS binding
Go to the Default website and at the right you should have an action “Bindings”. See the image above. Press the bindings.
My bindings for the Default website look as following:
IIS application bindings
The issue we notice is that there is a binding defined for “http” but there is none defined for “https”. So let’s add a binding for HTTPS at our IIS application. Press the Add button.
Select the “https” type in the binding types, make sure the Port is 443 (it is the default port for https). Notice you also need to select an SSL certificate for the HTTPS binding. However at this time we can not select any certificate yet in the list, which does not allow us to add the https binding. The certificate is needed for securing the transport channel by encryption.
Add https binding

4. Creation and configuration of the HTTPS self-signed certificate

To be able to add the HTTPS binding to our default website, we will need to create a certificate which we can use for HTTPS transport security.
In my opinion, this is where things start to get challenging. If you are not aware what a certificate is and how this actually works, this can be hell. To complete the IIS service configuration, we will first show how to create the certificate, configure IIS to use it. In the next chapter we will dig a little deeper into what certificates are and how they are used, so that you are also aware of why you are executing certain commands.
Open the visual Studio 2010 Command Prompt, which you can find under the Visual Studio Tools:
Visual studio 2010 commandline SDK

We will execute following command:
makecert –pe –n “CN=localhost” –sr localmachine –ss my –sky exchange
IMPORTANT: If you copy it from this blog post, it might fail and say too many parameters are used. Try to write it manually and execute it then. The quotes are being changed by this blog post. 

Makecert commandline for https certificate

After executing the command, it should say “Succeeded” at the command line.
What does it mean in a nutshell: Create a self-signed certificate for exchange purposes (https) in the localmachine store with the name “localhost”.
Since our domain is “localhost”, we create a certificate with “CN=localhost”. If your domain would be “www.dummiesforlife.com”, your certificate would be created with “CN=www.dummiesforlife.com”.
Self-signed certificates are good for development purposes. Once you want to go to production environment, please get verified certificates from certificate vendors like VeriSign.

There are a lot more options available for “makecert”. You can find more on the msdn documentation: http://msdn.microsoft.com/en-us/library/bfsktky3(v=VS.100).aspx

We created the certificate which we will use for the HTTPS transport security, so let’s see if the certificate was created. At run enter “mmc” and press enter.
Go to File – Add/Remove Snap-in … and you should be at the following screen:

MMC module

Select “Certificates” and press “Add”.
On the next window select “Computer account” and press Next. On next screen press Finish
MMC certificate configuration
It should look like this:
 MMC Certificate configuration
Press OK and you should be able to see the following:
At the Local computer certificates in the Personal Store (=My), in the certificates folder you should see a certificate called “localhost”, which is the certificate we created by command line for the https security.
Self-signed transport security certificate
Go back to the Default website in IIS and press the bindings action at the right. Add a new binding:
Select the localhost certificate in the SSL certificate list and press OK to add the binding
Add https binding in IIS
Revisit the EmployeeService in your web browser. The previous error should be gone and you should see the following:
The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'SslNegotiateCert'
The SSL settings of the service do not match the SSL settings of the IIS application. With other words, what we configured in the web.config does not match what is configured in IIS.
Let’s set the correct SSL settings in IIS for our “WCF.Tutorial.TransportSecurity.Service”, which should match our configuration of our service.
IIS SSL settings WCF service
Check “Require SSL” and set Client certificates to “Require”. This will match what we defined at our service application.
HTTPS transport with client credential authentication
Our configuration of our WCF service binding was as following:
HTTPS WCF Service Transport Security
We defined on our binding we are using Transport security, which in our case is HTTPS/SSL. Thus we set “Require SSL” to true, since our service will only be accessible by HTTPS-transport, a secured channel. We also set our clients that want to consume the service, should authenticate by Certificate. Therefor we set our IIS settings for “Client certificates” to “Require”. They MUST authenticate by certificate to our service, otherwise they will not be granted access. Only clients which certificates we trust are allowed access, all others are denied.
After the IIS changes made, let’s revisit our WCF service:
http://localhost/WCF.Tutorial.TransportSecurity.Service/EmployeeService.svc
The result you should be getting:
HTTPS secured WCF Service
We get an error that we are not allowed access to the service, that it is SSL secured. This of course makes sense, as we are browsing to it over “http” instead of the secure “https”, and we made the service only accessible through https. So let’s go through https now:
You might get a warning that the certificate is not trustworthy, which is normal in our case, we will come back to this later in the next chapter:
Just press “Continue” to continue to the service.
HTTPS certificate warning
And we get another nice screen of death:
WCF Service Client certificate required
“The page we attempt to access requires us to have a SSL client certificate that the web server recognizes”.
Well this is an error we like. To access the service, we need to have a client certificate to authenticate ourselves, and the client certificates has to be recognised and trusted by the web server.
The next step in our solution, is to add some functionality at our Client Console Application.
What has to be done for our Client Console Application:
  1. Create a proxy that can consume the secured WCF Service
  2. Have the correct configuration for our proxy and service endpoint
  3. Create a client certificate that our proxy can send to authenticate to the WCF service
  4. Make sure our web server, which hosts our WCF Service, recognizes the client certificate and trusts it, so access is granted

With other words, we are close to have a running solution. Our WCF Service is configured correctly and is hosted within IIS now.
But before we can finish our client application, we should look a little deeper into certificates, what they are and what they are used for.


5. Certificates, what are they and what are they used for

An SSL certificate is used for secure conversations:
  • Assures the identity of the provider
  • A point-to-point encryption between the service and the client

Actually I found a great and easy YouTube video which explains the basics of SSL certificates in human words and only in 3 mins. I suggest you watch the video first:
http://www.youtube.com/watch?v=zPqtx1J6udc&feature=youtu.be

When a service is secured by TLS/HTTPS and a client wants to consume to service, a handshake has to take place first, to set up the secure channel in which the exchanged information is encrypted, so people with bad intentions can not simply sniff the data off the network and read the contents.How does the handshake work in a quick overview:
Transport Security SSL HTTPS handshake

There’s a few important things to notice here.

  • A certificate contains a public and a private key
  • The browser ensures that the certificates is unexpired, unrevoked, issued by a trusted party and that its common name matches the website that it is connecting to
  • The private key is used to decrypt the symmetric key created by the client, which was encrypted by the certificate’s public key.

When the client requests a secure conversation with the server, the server returns its certificate and its public key. The client generates a symmetric key and encrypts this symmetric key with the certificate’s public key and passes this encrypted symmetric key to the web server. This encrypted symmetric key can only be decrypted by the private key of that certificate, and the private key is never being traded, it always remains on the server. The private key is highly confidential and the web server is the only one having the private key. As the symmetric key encrypted with the exchanged public key is only decryptable with the private key, the server is the only instance able to decrypt this encrypted symmetric key and get the same symmetric key as the client has. If someone would have been sniffing the handshake, he would only get an symmetric key, which he can not decrypt because he does not have the private key … As only the server can get the symmetric key by decryption, we are setting up a secure channel. Both the client and the server will have an identical symmetric key, which nobody else can have if the private key is safe, and all communication can from this point on be encrypted with the symmetric key, which both sides have and which people with bad intentions do not have.

As mentioned above, one of the issues which might arise when using transport security, is that the web server does not have enough rights on the private key. At some point, the web server will get an encrypted symmetric key which it has to decrypt with its private key. If the web server does not have enough rights to this private key, it will fail to decrypt the encrypted symmetric key and the handshake will fail, resulting in an error.

If this issue would occur, you can solve this by managing the Private keys of your certificate that you use for the transport security as following:
Manage certificate private keys

If your application pool under which your IIS application runs is for example “Network Service”, then you would have to add Network Service to the users that have access to this private key and make sure it has read rights to the private key, so that it can retrieve the key from the local machine to decrypt the encrypted symmetric key.

As also mentioned in the things to notice, the common name of the certificate has to match the domain name of the website it is connecting to. In our case our domain is localhost as we are running it in IIS locally. If our website would be hosted on a domain http://www.website.com, our certificate subject would be “www.website.com”.

There are 2 ways to get a certificate. One is creating a self-signed certificate and the second is to buy a certificate which is issued by a trusted certificate authority, like VeriSign.
Self-signed certificates are only good for development purposes. Thus once you want to go into production with your application, you will need to get a certificate from a verified certificate authority. These authorities will issue the certificate for you and the subject of the certificate will be your website domain name. This way the certificate will also guarantee the identity of the website to the client by the SSL certificate, as these authorities will not issue multiple certificates for one and the same domain.

These certificates are issued by authorities, like VeriSign, Thawte, GoDaddy and a few others. These are “recognized” certificate authorities. If you want to have a valid certificate which can be trusted by clients, your certificate will have to come from one of these recognized certificate authorities. These recognized certificate authorities is what we call a trusted root certification authority“,  a global trusted authority that issues SSL certificates for secure communication.

You can find these trusted root certification authorities in your certificates MMC:

Trusted root certification authorities

If we now look at our self-signed certificate called “localhost”, which we created in one of the previous steps.
Go to personal certificates on your local computer certificates, and double-click the localhost certificate, which we use for our Transport security of our WCF service

SSL certificate properties

In the image above you can see our certificate image has a red cross added to it and there is a notification “This certificate cannot be verified up to a trusted certification authority”. It also says it is Issued by “Root Agency”. Root Agency is the default Root authority your self-signed certificate belongs to, if you have not created your own self-signed root authority certificate, which we have not.

So this actually means when the client tries to set up a transport secured channel with our service, it will most likely get an exception because the SSL certificate used by the server is not verified by an instance that is at the “Trusted root certification authorities”!

If you look at the Certification path of the localhost certificate properties, you will see that the “Root Agency” certificate shown the following error:
“This CA Root certificate is not trusted because it is not in the Trusted Root Certification Authorities store”.


Certificate root path

It says the root authority of our self-signed certificate is not present in the Trusted Root Certification Authorities.
Our default Root Authority is called “Root Agency” with our self-signed certificate.
If we looked in our Trusted Root Certification Authorities in our local computer, we see there is NO “Root Agency” certificate installed, which means our “localhost” certificate will not be trusted if we have a client on this computer trying to set up a secure transport channel with your service.

Certificate Root Authorities

If we could have a client proxy and we try to consume the service (and pass a valid client authentication certificate), we would get the following error:

Could not establish trust relationship for the SSL/TLS secure channel with authority

It will say “Could not establish trust relationship for the SSL/TLS secure channel with authority ‘localhost'” because the root authority that localhost has is not installed on the Trusted root certification authorities on the machine the client is on (In our case this is the same machine as the service).

To be working with self-signed certificates, it is useful to have a self-signed root authority which issued the self-signed SSL certificate. There are 2 ways:

  • First create a self-signed root authority and install it in the “Trusted root certification authorities”. Secondly create a self-signed SSL certificate (like localhost) but with the private key of that root authority your created. This way the self-signed SSL certificate will be linked to a trusted root certification authority, which you also self-signed.
  • Do it the same way as we did with our self-signed certificate. Create first your self-signed certificate and afterwards make sure the default “Root Agency” certificate is installed in your Trusted root certification authorities.

Since we first created the SSL certificate, let’s go with the second method and make sure our “Root Agency” is a valid Trusted root certification authority.

If you want to create your own Root CA certificate and Root CRL certificate, you can find how to on this post at section 8.What if you insist on creating your own ROOT CA certificate and ROOT certificate revocation list (CRL)
WCF Message Security and client certificate authentication with self-signed certificates

Go to the personal certificates of your local computer, where our SSL localhost certificate is, double hit the localhost certificate and go to the Certification Path of the certificate properties:

Create a self-signed trusted root certification authority

Double click the “Root Agency” in the Certification path, which will open the Root Agency certificate:
Note how it says “This CA root certificate is not trusted. To enable trust, install this certificate in the Trusted Root Certification Authorities store”. How nice, it actually says how we can solve the trust issue

Install root authority certificate

Go to the tab Details and press the button “Copy to file”, which will start a wizard to export the certificate, so that we can import this certificate in the Trusted root certification authorities:

Export self-signed certificate

Press next:

Export SSL certificate

Press Next, Select a location on your machine where to store the certificate and call it “Root Agency”, Select Next and Press Finish:
It should say “the export was succesfull”. At the location where you stored the certificate, you should have a .cer extension certificate:

Exported certificate to import

Now we exported this certificate, so we can import it into the Trusted root certification authorities:
Go to the Trusted Root certification authorities, right click the certificates folder, go to all Tasks and press Import:

Import certificate

Press Next on the start of the wizard and on the next window select the certificate we just exported in the steps above, so we can import it now:

Import root certification authority

Press Next:

Import self-signed certificate into store

Notice that the certificate store in which we import this certificate is “Trusted Root Certification Authorities” is, the store where all trusted root authorities are that issue trusted certificates.
Press Next and press Finish. The import should succeed. Now you should be able to see the “Root Agency” certificate in the root authorities store:
Trusted root certification authority for self-signed SSL certificate

If you go back to the localhost SSL certificate, which we created ourselves and go the properties of the Certification path, you should see the Root Authority is not valid for our SSL certificate:

Root authority certificate validation

There are a few very important things to remember:

  • Every certificate has a Root authority. If it is self-signed and it does not have a valid Trusted Root Certification Authority, an exception will be thrown at the client which is trying to consume the service, that it could not  establish a trusted TLS/SSL channel, because that Root authority is not present in the trusted root certification authority of the client. Once it is, the trusted TLS/SSL channel will be established.
  • If you create or import, like in this tutorial, the root certificate authority in the root authority store of your machine of the service, and your client is on another machine (somewhere over the internet, we don’t know where), your client will not be able to establish a trusted TLS/SSL channel, because the client does not have this Root Authority certificate we created into this trusted root authority store!! Only the recognized certificate authorities, like VeriSign and  Tawthe etc are by default in the Trusted Root Certificate Authorities. Your self-signed or imported root authority certificate is not, so it will fail, unless you add some code to the client like this, though this is not advised: ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate{return true;});
Some other certificate details which you need to know off:
Self-signed certificate thumbprint
A certificate is valid between a certain period. In our self-signed case, this is a very long time. When a client tries to set up a secure channel with a service, it will validate the expiration date of the certificate that is passed from the server to the client. If the expiration date is no longer valid, the setup of the secure channel will fail and communication will not be possible.
The certificate has also a subject and a thumbprint. The subject is the domain name we passed when creating the certificate, without the “CN=” and the thumbprint of the certificate is the certificate identifier. Every certificate has a unique thumbprint. You can find certificates by thumbprint, subject name, expiration dates etc. These details can be used to get a certificate from the store.
If you remember configuring the WCF Service in the web.config, at some point we wrote something like this:
WCF transport security behavior configuration
We set the certificateValidationMode to “PeerOrChainTrust” at the clientCertificate authentication. Untill now we talked about certificates used for Transport security, creating an SSL/TLS channel for secure communication. But you can also create certificates for client authentication and that is where the certificateValidationMode comes into the scenery.
There are a few certificateValidationMode’s possible:
certificateValidationMode clientcredentials
If the client provides a certificate for authentication and the certificateValidationMode on the service is set to
  • PeerTrust: the certificate that the client provides to authenticate, should be at the “Trusted People” certificate store.
  • ChainTrust: the certificate should be issued by a trusted root certification authority and that authority has to be present at the “Trusted root certification authority” certificate store.
  • PeerOrChainTrust: both the above combinations are possible.
The default value is ChainTrust. We selected PeerOrChainTrust as validationmode, so if the Root Agency is present in the Trusted root certification authority certificate store, the client certificate will be validated for authentication if it is also issued by the same Root Agency. We could also validate the client certificate for authentication, by adding the client certificate to the Trusted people certificate store, which we will do for the authentication of the client certificate.

6. Consume the WCF Service by the client and authenticate with a client certificate to the service

After a wall of text, let’s finalize our solution and add some functionality to the client console application so that it can consume our WCF service, provide a client certificate for authentication, make sure that certificate can be validated at the server and is granted access.
We work at the “WCF.Tutorial.TransportSecurity.Client” project, which is our Console application, which generates our client behavior.
Add a reference to:
  • System.ServiceModel
  • WCF.Tutorial.TransportSecurity.Service (Projects tab at the Add Reference dialog)

We are adding a reference to the service project because our interface for our service is there. We can easily create a proxy to consume the service by ChannelFactory<interface> without much hassle.
In a real scenario, you would put your interface in a separate library, so that you could share the interface only with other businesses, or you would just share the WSDL of the service with other businesses. But since this is a demo, we just add a reference to our service project.

If there is no Application Configuration File present yet, add a new one (app.config).

Now we need to configure the client app.config so that it can communicate with the WCF service hosted on https://localhost/WCF.Tutorial.TransportSecurity.Service/EmployeeService.svc

WCF Client Configuration

As always, our configuration comes within . Since we are at the client, and not the service, we need to add a section with an defined of which the address is the absolute uri of the WCF service we created. The binding is a basicHttpBinding, the same binding as our WCF service and the contract is “WCF.Tutorial.TransportSecurity.Service.IEmployeeService” which points to the Interface of our EmployeeService at the Service project. We also set the bindingConfiguration to a basicHttpBinding config, which matches the same binding as the one on the service, defining we use Transport security with clientCredentialType of certificate.

The configuration above should look familiar, as it looks almost the some of the configuration we defined at our Service. The only thing left we need to add at the configuration of our client side, is the client credential certificate, specifying what certificate our client application should use to authenticate to our WCF Service. However before we can do that, we will first need to create a certificate the client can use for authentication.

We create a self-signed client certificate for authentication with the following command (in the visual studio command line prompt again):
makecert -pe -n “CN=client” -sr localmachine -ss my -sky signature

Create client authentication certificate self-signed

This command looks almost identical to the command we used for the SSL certificate for transport security, the only difference is that the -sky parameter is set to “signature” instead of “exchange”.
The -sky parameter of the makecert command specifies the subject’s key type, which is either signature or exchange.
  • Signature: Indicates that the key is used for a digital signature
  • Exchange: Indicates that the key is used for key encryption and key exchange
Setting up the transport security channel with SSL certificate, we need the key type exchange, as we use the key for the symmetric key encryption.
After executing the command, we should have a certificate called “client” which we use for client authentication.
Client certificate
NOTE: Because our client and our service are on the same computer, both the certificates are in the same personal store. In a client-server scenario, the localhost certificate will be on the server machine certificate store and the client certificate will be on the client machine certificate store. Please make sure you are aware of the difference.
As we said we would validate the client certificate at the WCF service by PeerTrust, we need to add this client certificate to the “Trusted People” certificate store on the server machine certificate store (in our scenario, this is all on the same machine again, but in a split scenario, this would be on the Trusted People store of the Server machine certificate store).
To import the client certificate in the Trusted People, we need to export our client certificate from the personal store, trade it to the service administrator and he can import it to the Trusted People. Once that happened, you are able of accessing the service with authentication of that certificate.

The above scenario is almost equal to exporting and importing a certificate as before, so I will not include screenshots. Execute the following steps:

  1. Go to the Personal store on the local machine certificate store on the Client machine
  2. Right click the “client” certificate, go to All Tasks and press Export
  3. Press Next
  4. Leave it to “No, don’t export the private key” and press Next
  5. Leave it to “DER encoded binary X.509 (.CER) “ and press Next
  6. Select a location where you want to store the client certificate and call it “client” and press Next
  7.  Press Finish and the certificate should be created at the location you specified
  8. Go to the “Trusted People” certificate store on the Server machine where we host the Service (in our case the same machine), right-click, go to All Tasks and hit Import
  9. Press Next
  10. Select the client.cer certificate at the location you chose before at the export (or if you traded it with an admin, where-ever the admin placed it after trade) and Press Next
  11. Press Next, again Next and then press Finish
You should have the following result if everything went correct:

Client certificate Trusted People certificate store

Now that we created the client certificate for authentication, set it at the right store, we need to configure our client console application so that the endpoint at our <client> uses the certificate to authenticate to the service.
We will add an endpointBehavior (Note this is an endpointbehavior, and not a servicebehaviour as it is on the service side) that specifies the clientCredentials for the client to connect to our EmployeeService. We set the clientCredentials to a clientCertificate (aka authenticate by certificate to the service) and therefore we need to specify 4 values.

Client certificate authentication behavior

  • StoreLocation: At what store our client certificate is. In our case this is LocalMachine. You can choose between CurrentUser and LocalMachine
  • StoreName: At what store our client certificate is, depending on the storelocation. In our case this is “My”, which means the Personal store
  • X509FindType: Defines by what certificate detail you want to search for the certificate. We use FindBySubjectName, which searches the certificate by subject
  • FindValue: The value it searches for on the certificate details, depending on what detail we want to search on, which is defined in the X509FindType

We set it to look for a certificate by subject name “client”, which will return our client certificate:

Client certificate subject

We defined the endpointBehavior, now we need to make sure our endpoint also references to that behavior we created. This is the result:

EndpointBehavior clientcredential certificate

Now we only need to add some code at our program.cs, that will create a proxy that tries to connect to the WCF service, authenticates to the service by the client certificate, calls the GetEmployee operation and gets a result back. If all this works, we have set up Transport Security with certificate clientcredential:

ChannelFactory proxy

In code we create a channelFactory<WCF.Tutorial.TransportSecurity.Service.IEmployeeService) with the endpoint “serviceEndpoint”, which is the endpoint name we specified in section of our client configuration and we create the channel for communication. On the next line we call the operation GetEmployee and we pass my name along. The result that is returned we write to the console to see if the communication works.

If we now set our client console application as startup project and we run the client, we get the following:

WCF Transport Security with client credential authentication

Considering the following:

Service implementation

We should have gotten as result “Employee information: Robbin Cremers”, which was also the result we gotten. This means the channel was secured with Transport Security and the client has to authenticate by a client certificate, which is trusted by our service’s web server. If you try to create a client which attempts to call this operation without providing the client certificate, access will be denied!
Any suggestions, remarks or improvements are always welcome.
If you found this information useful, make sure to support me by leaving a comment.

Cheers and have fun,

Robbin

31 comments on “WCF transport security and client certificate authentication with self-signed certificates

  1. Is there a way to setup all client side configuration via code? I am utilizing services in unit tests and I’d like to setup everything via code rather than app.config.

    • Yes, you can write all the WCF configuration through code-behind. It’s gonna look very similar, but you’ll be using the code implementation classes under the System.Servicemodel. It’s pretty straight forward and you don’t have to use any configuration at all if that’s what you want.

  2. I enjoyed reading this. It is informative and complete while also being well written, making it effortless to learn something new.

    Every step is explained well and reasons given so that I did not just blindly follow along, but understood the theory behind what I was doing as well.

    Thank you sir!

  3. Hi Robbin.

    I have done all the steps correctly. But i have got the below error.

    The SSL settings for the service ‘None’ does not match those of the IIS ‘Ssl, SslNegotiateCert, SslRequireCert, SslMapCert, Ssl128′.

    I have hosted the service in the IIS. Is it microsoft bug ?. Please help.

    http://support.microsoft.com/kb/972251

    • It means the settings in your web.config do not match the SSL settings of your IIS application. If your configuration of your web.config does not require SSL, but your IIS application says SSL is required, you will get an exception because they do not match.

      Check the SSL settings in your IIS application and check your web.config. Something will not be configured correctly in one of these.

  4. hello mr robbin
    Can you give me the this project source code?
    and I have question
    Can I run a thumbprint on the wcf authentication service?
    Can you give me the source?
    thanks

    thanks

  5. Hi Robbin,

    It is really good.
    I am getting this error.
    Server Error in ‘/WCF.Tutorial.TransportSecurity.Service’ Application.
    ——————————————————————————–

    Security settings for this service require ‘Anonymous’ Authentication but it is not enabled for the IIS application that hosts this service.

    Is there an solution other than enabling the “anonymous” ?

    Thanks
    Benn

  6. This works for me. Thanks. But, when I try to browse to the URL using the fully qualified domain name (FQDN) i.e. mycompanyname.com instead of localhost it fails with error “Could not establish trust relationship for the SSL/TLS secure channel with authority ‘mycompanyname.com’

  7. Hello , Nice article. Could you please post the implementation steps for “WCF Dual security with Mode=”TransportWithMessageCredential” and client certificate authentication with self-signed certificates”. Something like

    Any help would be appreciated.

    Thanks,
    Sujith

  8. Explained in very fine details, exactly what I was looking for to understand how it works.

    I am getting an error though, the inner most exception is:

    “The remote certificate is invalid according to the validation procedure.”

    I followed your instructions to the letter.

  9. Hi Robbin,
    I am having the same issue as Piyush, I can use any certificate to get access to the service. Is there something wrong I am doing.. I have not installed the public key of the client in the trusted people.. but still I can access the service with any self signed certificate I create.. can you please help?

  10. The Root Agency certificate does not say “This certificate cannot be verified up to a trusted certificate authority.” Instead, it says “The integrity of this certificate cannot be guaranteed. The certificate may be corrupted or may have been altered.” When I try to add Root Agency to the trusted certificate store, it gives the same error.

  11. Pingback: WCF Transport Security with Certificate authentication | SudhakarAdapa

  12. Am getting this error..Please help
    The HTTP request was forbidden with client authentication scheme ‘Anonymous’.

  13. Thanks for this very helpfull article!
    Do you know if it will work with Silverlight as a client? Silverlight does support httpBinding but I cannot set this at the client:

  14. Thanks for this really good post. After reading from Windows Communication Foundation 4 Step by Step form Microsoft and of course your post, i was able to deploy my service and establish communication to it. I’m in a production environment with real servers and real certificates. Just one thing i want to comment with you is, when you set up all the service security and you get the end of part 4 of your post, at that moment you are not able to add the service reference using the add service reference option of Visual Std. So what i did was to disable Require SSL in IIS where the service is deployed and then you’r able to add the service reference, and turn on the feature again once you have the reference.

  15. I am getting “Additional information: The HTTP request was forbidden with client authentication scheme ‘Anonymous'”. Please help, Why am I getting this?

  16. You really make it seem so easy along with your presentation however I find this matter to be really one thing that I feel I’d never understand.

    It seems too complex and extremely vast for me.
    I’m having a look ahead for your next submit, I’ll try to get the cling of it!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s