WCF – 2 Way SSL Security using Certificates

I had to work extensively in this topic, and had to go through hundreds of blogs and articles to finally make it work. It’s actually pretty simple but for someone who is new to WCF, it might give a few sleepless nights and some terrible days.

This article assumes that you have a decent knowledge on WCF, IIS hosted WCF Services, transport security and digital certificates.

Configuring the Service:

Open your Service’s web.config file and edit it’s binding configuration as below:

 <bindings>
<wsHttpBinding>
<binding name="CertificateWithTransport">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>

The above binding configuration uses wsHttpBinding with Transport mode security. You can also notice that the clientCredentialType is mentioned as “Certificate”. It means, that the consumer of the service is authenticated using a certificate.

Your behavior section should look like this,

<serviceBehaviors>
<behavior name="BindingBehavior">
<serviceMetadata httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="true"/>

       </behavior>
</serviceBehaviors>

Notice that the httpsGetEnabled=”true” attribute. It tells WCF to serve get request on the service. This is should be set to true when you want the consumers to get the wsdl themselves.

If this is set to false, no one will know about this service, unless you give them the wsdl file for consumption. Most of the enterprise services do set this attribute to false for security reasons.

Your Services section should look like this,

<services>
<service behaviorConfiguration="BindingBehavior"
name="servicename">
<endpoint binding="wsHttpBinding" contract="SSPNotificationReceiver.IReceiverService" bindingConfiguration="CertificateWithTransport">
</endpoint>
<!--<endpoint address="mex" binding="mexHttpsBinding"
name="MetadataBinding" contract="IMetadataExchange"/>-->
</service>
</services>

The above behavior configuration basically exposes an endpoint with information about the binding type, service contract type and the binding configuration. The bindingConfiguration attribute is the link between the binding settings and the endpoint, and the behaviorConfiguration attribute is the link between the behavior settings and the service settings.

The commented endpoint is for the meta data exchange. Since we are using SSL, the meta data exchange is also secure. But beware, may be this is the most important statement in the entire article. There is something very important about commenting this part at the end of the article.

Setting up IIS and creating the Certificates:

Now, publish the service on IIS using Visual Studio. The following screen shots show you how to configure the IIS SSL mappings.

The following example will show you how to create SSL Server and SSL client certificates using a Certificate Authority running on Windows Server 2003. You can also create your own certs for development through makecert.exe. There are multiple articles on the internet showing how to create certificates using the tool. Just do a Live Search and find out.

  • Set Anonymous Access on IIS for your website (another important task which you might easily miss out) and remove all other authentication modes.

image

  • On the Directory Security tab, click Server Certificate and choose “Create new Certificate”. Follow the wizard to generate the certificate request. The certificate request is by default created in “c:\certreq.txt”
  • Open the Certtificate Services Website. It is generally http://localhost/certsrv on the server which is running the certificate authority.

image

  • Click on the Request a Certificate link

image

  • On the next screen, click on advanced certificate request

image

  • Choose the second option in the above screen

image 

  • In the next screen, paste the contents of the c:\certreq.txt file in the saved request textbox as shown above.
  • After you click submit, the certificate is created and queued in the Pending Requests on the Certificate Authority.
  • Open Certificate Authority in the Windows Server 2003 machine

image

  • Issue the certificate.
  • Again, go back to the Certification Services and click on the “View Status of the pending requests” link in the home page.

image

  • Click on Download Certificate link and save the certificate to a location and name it SSLServerCert.cer

 image

With this, you have successfully created the SSL Server Certificate which can be used for Server Authentication purpose.

Follow these steps to create a Client Authentication certificate.

  • On the Certificate Services home page, click on Request a Certificate option which will take you to the page shown below.

image

  • Click on advanced certificate request option in this page.
  • In the next page, click on “Create and submit a request to CA” option
  • Choose “Client Authentication Certificate” in the Type of certificate needed drop down.
  • Give all text boxes with appropriate information in the Identifying Information section.
  • Check “Mark Keys as exportable” option

image

  • Click Submit
  • As you did for SSL Server Certificate, go to Certification Authority and Issue this certificate as well
  • Come back to the Certificate Services again and click on Install Certificate link

image

  • Your Certificate will be installed in your Personal Store as shown below

image

  • You can export this cert with private key and send it across to the client who is going to use the certificate for authenticating itself.

Configuring IIS for 2 Way SSL Authentication

  • On your website’s directory security tab, click on Server Certificate
  • Click next and choose the option as shown below

image

  • Follow the wizard and select the SSLServerCert.cer that you already saved
  • Once finished, again click Edit button in the Secure Communications Section in Directory Security tab.

image

  • Check the Require secure channel (SSL) option
  • Choose Require client certificates under Client Certificates section

Do not do the following steps if your service needs only SSL Server Authentication. To enable SSL Client authentication also, proceed with the following steps

  • Check Enable client certificate mapping option
  • Click Edit to create a 1-1 certificate mapping
  • Browse to the client certificate that you already created and give map a local user account to it. All requests that carry this certificate will run using the account that you give here
  • Now, you have completed the entire hosting part of the service. The Service that you created is secured by SSL Server as well as SSL Client authentication.

Configuring the client to use SSL

<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IReceiverService">
<security mode="Transport">
<transport clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address=https://YourIP/ReceiverHost.svc behaviorConfiguration="credentialConfiguration"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IReceiverService"
contract="NotificationProxy.IReceiverService" name="WSHttpBinding_IReceiverService" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="credentialConfiguration">
<clientCredentials>
<clientCertificate findValue="99bbc6c9e6f4a6bd526bc8bb21f9c21f0716c23r"
storeLocation="CurrentUser"
x509FindType="FindByThumbprint" />

              </clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
</system.serviceModel>

I have pretty much posted the entire client configuration here. There is nothing very different from the service configuration, but for the behavior and the endpoint address.

Now, you are all set to access the service through the client.

You can access the service using the browser too..

When you do so, the browser (IE) pops up a window showing all the certificates installed in your personal store. You need to select a the certificate that you already installed in it

image

Select the appropriate certificate to view the service screen.

image

That’s it. Your service is up and running on IIS, secured using 2 Way SSL Authentication.

Two most important things not to forget:

As I said earlier there are two things that you should do:

NEVER FORGET TO ENABLE ANONYMOUS ACCESS ON IIS.

NEVER FORGET TO COMMENT THE MEX ENDPOINT ON THE SERVICE CONFIG

These two things are the most crucial part of this entire process. WCF, for some reason that I don’t know, wants Anonymous Access to be enabled on the website. You will get this error if you don’t do so.

Exception: System.ServiceModel.ServiceActivationException: The service '/ReceiverHost.svc' cannot be activated due to an exception during compilation. The exception message is: Security settings for this service require 'Anonymous' Authentication but it is not enabled for the IIS application that hosts this service.. --->

Next, if you forget to leave the mex endpoint uncommented, you might end up seeing this error on the event log of the service.

Exception: System.ServiceModel.ServiceActivationException: The service '/ReceiverHost.svc' cannot be activated due to an exception during compilation. The exception message is: The SSL settings for the service 'None' does not match those of the IIS 'Ssl, SslNegotiateCert, SslRequireCert, SslMapCert'.. –->

As you can see, this does not convey any reasonable thing to you, leave alone suggestions to fix the error. Be careful with these two settings.

Enjoy WCF !!

Comments

  • Anonymous
    December 10, 2008
    Hey I got nice help from blog. but I am still endup with Exception. "The SSL settings for the service 'None' does not match those of the IIS 'Ssl, SslNegotiateCert, SslRequireCert, SslMapCert'" If i change trasport secutity from "trasport" to "trasportwithMessageCredential" It works. But again I end up with "Could not establish trust relationship for the SSL/TLS secure channel with authority" Can you tell me the cause.

  • Anonymous
    December 10, 2008
    For this error "Could not establish trust relationship for the SSL/TLS secure channel with authority", check that the SSL Certificate that you have is trusted on the client. That is, the SSL certificate issuer should be in the Trusted Store of your client computer. If your SSL certificate is issued from a Trusted CA like Verisign,you shouldn't be facing this problem because all of the known Verisign issuers are already trusted. However, if you are testing with a temporary certificate which you created using makecert.exe or got from a test CA like Comodo, you will face this problem. If you still want more clarifications, let me know what kind of binding configuration you are using, so that I can help you out with the right settings. Good luck.

  • Anonymous
    December 11, 2008
    Excellent description. Keep up the good work.

  • Anonymous
    December 14, 2008
    Good blog. Thanks. I am a little confused about anonymous access too. Can you write a wcf service that just uses anonymous access without encryption and without windwos authentication? I know you would not want to do this, but want to know if you can. Otherwise is it safe to assume all wcf services must use certificate based authentication?

  • Anonymous
    December 14, 2008
    You can always set the WCF service to use no authentication at all. Of course no one would want to do that, but its possible. On your second question, it is not required for all WCF services to use certificate based authentication. WCF Services must be configured for SSL client certificate authentication only if the clients are already "known" to the service. (ie., Intranet applications or when you have a defined set of customers to access the service) Internet based non-critical services generally don't use client certificates.

  • Anonymous
    January 07, 2009
    Someone copied your post here: http://codingtkj.blogspot.com/2008/12/2-way-ssl-security-using-certificates.html

  • Anonymous
    January 07, 2009
    You can leave the mex endpoint uncommented if you configure it to use wsHttpBinding and the same bindingConfiguration as your service uses.  For example, <endpoint address="mex" binding="wsHttpsBinding"  name="MetadataBinding" contract="IMetadataExchange" bindingConfiguration="CertificateWithTransport"/> For more info see: http://msdn.microsoft.com/en-us/library/aa395212.aspx (Custom Secure Metadata Endpoint)

  • Anonymous
    February 23, 2009
    Nice and useful article! But even after enabling anonymous in IIS and disabling mex, I still get errors: Service error: The HTTP request was forbidden with client authentication 'Anonymous'. Service Fault: The remote server returned an error: (403) Forbidden. What could be the reason?

  • Anonymous
    April 27, 2009
    The comment has been removed

  • Anonymous
    April 27, 2009
    The comment has been removed

  • Anonymous
    May 12, 2009
    great article. but when i checked the Require SSL in iis (7.0). then every time i get Internal Server Error. why?

  • Anonymous
    May 12, 2009
    i found out that if iis is configured as Require SSL, i had 2 comment the HTTP binding/endpoint swctions  in the web.config to get it to work. why?

  • Anonymous
    May 20, 2009
    I was able to get the MEX endpoint to work using this same approach. The issues is the binding and bindingConfiguration of the endpoint. Step 1 was to create a service behavior that required SSL.    <behaviors>      <serviceBehaviors>        <behavior name="MyName">          <serviceMetadata httpsGetEnabled="true" httpGetEnabled="false"/>                  </behavior>      </serviceBehaviors>     </behaviors> Step 2 is to enable the MEX endpoint using the wsHttpBinding and proper binding configuration. In this case, the binding configuration is the same as the primary endpiong name. <endpoint address="mex" binding="wsHttpBinding" contract="IMetadataExchange" bindingConfiguration="MyBinding" /> Doing this worked fine. To get to the MEX endpoint, a client cert is required - which is exactly what I wanted.

  • Anonymous
    May 20, 2009
    Meir >> I can't get your problem. Can you post your bindings as well?

  • Anonymous
    June 09, 2009
    Awsome Work! But i'm still expirencing some trouble. I can create an instance of the service, but i can't call any methods. i recieve an errormessage like: "could not establish trusted ssl/tsl channel..." any ideas? Regards Jaster

  • Anonymous
    June 09, 2009
    It's basically a certificate trust issue. The client machine that you are using to talk to the server does not trust the certificate that you are using on your server. Make sure the certificate's 'CN' property has the domain name. Eg., If the WCF Service URL is : https://myserver/services/service.svc then, your certificate should be issued to "myserver". i.e., you should see CN=myserver in the certificate properties. If this is also done, then install the certificate in the trusted store of the client machine. It should work.

  • Anonymous
    June 21, 2009
    Very Good Article, follwoing your steps I was able to install my service using SSL. Although few of my steps somehow differ than what it has stated in the article. I will comeback to later on that. First I have few questions in code below (Configuring the client to use SSL) which certificate thumb print represents below Client or Server? My second question is how do I know what's the value of storeLocation? <behavior name="credentialConfiguration"><clientCredentials><clientCertificate findValue="99bbc6c9e6f4a6bd526bc8bb21f9c21f0716c23r" storeLocation="CurrentUser" x509FindType="FindByThumbprint" />

  • Anonymous
    June 21, 2009
    Chowdhury, In the behavior, you must give the client certificate's thumbprint value. In the storeLocation attribute, give the name of the store where the certificate resides. There are multiple certificate stores on the computer and here is how you open them. On Run -> Type mmc and press Enter Press Ctrl +M On Add or Remove Snap-ins window, select Certificates and click Add button A new window with

  1. My User Account
  2. Service Account
  3. Computer Account appears If you select "My User Account", you will be able to see all certificates accessible to that particular windows user account. If you select Service Account, you will be able to see all certificates accessible to that particular windows service that you will eventually choose in the next window. Sample theory applies to the third option as well.
  • Anonymous
    July 28, 2009
    Thank you for the great post. The only problem we have noticed that once Anonymous is enabled on IIS, ANY certificate issued by CA that is in trusted authorities store is granted access. Is there a possibility to restrict access to just one specific Cert?

  • Anonymous
    August 01, 2009
    Hi, here are some good news and bad news. Good news is following your steps, I was able to install my service using SSL as well as consume the service from a client (console application). No issue. The app config file used for the client console application shown as below <system.serviceModel>        <bindings>            <wsHttpBinding>                <binding name="EmailServiceHttpsEndpoint">                    <security mode="Transport">                        <transport clientCredentialType="Certificate" />                    </security>                </binding>            </wsHttpBinding>        </bindings>        <client>            <endpoint address="https://tnsiit.tnsinsideit.local/EmailService/EmailService.svc"                behaviorConfiguration="credentialConfiguration" binding="wsHttpBinding"                bindingConfiguration="EmailServiceHttpsEndpoint" contract="EmailClient.EmailService.IEmailService"                name="EmailServiceHttpsEndpoint" />        </client>      <behaviors>        <endpointBehaviors>          <behavior name="credentialConfiguration">            <clientCredentials>              <clientCertificate findValue="c72e3caa4ae63e20791f10bc6ab99ef24a2cc34d"   storeLocation="CurrentUser"  x509FindType="FindByThumbprint" />            </clientCredentials>          </behavior>        </endpointBehaviors>      </behaviors>    </system.serviceModel> The bad news is after that I have created an ASP.net application, trying to consume the same service. I have cut & paste the above configuration into ASP.net web config, we I was testing the above service via aspx page, I'm getting this error Cannot find the X.509 certificate using the following search criteria: StoreName 'My', StoreLocation 'CurrentUser', FindType 'FindByThumbprint', FindValue 'c72e3caa4ae63e20791f10bc6ab99ef24a2cc34d'. Do I have to do something different for ASP .NEt  application. Any help will be really appreciable.

  • Anonymous
    August 05, 2009
    Thanks for a great post. I had a similar issue trying to figure out why a particular WCF service kept reporting that it needed anonymous authentication enabled in IIS, even after I corrected the items in the WCF service's web.config file. It turned out for me that even though web.config changes are supposed to be applied immediately after the file is saved, I had to issue an IISRESET command in order for the error message about anonymous access to go away.

  • Anonymous
    August 11, 2009
    Hi Imaya, This is a good article, and you being the original source, it has been shamelessly copied all over the internet by people claiming it as their own. Anyway, credit goes to you for the original. I wanted to point out a couple of things though. a) Setting anonymous is not necessary. You've had to set anonymous over there because your service settings are not properly translating the certificate identity into an identity that the service will understand, i.e. an AD identity for instance. Try doing the mapping using serviceBehavior/service-clientCredentials .. and you'll see what I'm saying. b) Metadata exchange does not need to be turned off either. You simply need to do httpsEnabled - true, or enable metadata over HTTPS as one other comment mentioned above. Great post otherwise. Love it. Sahil

  • Anonymous
    August 11, 2009
    Thanks Sahil. I appreciate your clarification for the issues mentioned.

  • Anonymous
    August 12, 2009
    Hi Imaya, Thanks for the great post. I exactly had the same issues, and your article pulled me out. My only grievence is I found you article when I had struggled thru and fixed almost all the issues, and was stuck at the last one - related to commenting the mex endpoint. Still a great post. Keep up the good work. Manav

  • Anonymous
    September 05, 2009
    Hi Imaya,thanks for your great post. By the way,what do you mean by terms of "2 way SSL security?" what is the typical usage scenario for it?

  • Anonymous
    September 06, 2009
    @Alex : It's just that the client will also have a SSL certificate so the server can authenticate the client. So, I call it '2 Way'.

  • Anonymous
    October 19, 2009
    hi imayak, thank you for taking your time and help us all. i have a problem =) before i found your post, i already figured out how to set up https on my dev machine running xp as well as my QA 2003 server with self certificate. my project (website) is a distribution website, therefore, i cannot use static url in the web.config or in the clientconfig. i find the Uri and create the proxy from there. everything works great! with two end points in the web.config file. 1 - basicHttpBinding 2 - wsHttpBinding hitting the wsdl with http or https works, however, when i set SSL Required on, i can't get to the wsdl at all. if i remove basicHttpBinding section or wsHttpBinding and remove httpGetEnabled (basicHttpBinding) or httpsGetEnabled (wsHttpBinding) out of the serviceMetadata, then it works. Question 1) Any thought? Question 2) do i need those end points in the web.config? Can i do it dynamically when i about to call WCF? I'm new to WCF as well, so if you or anyone knows how to create a dynamic end point w/out any end point in the web.config, please feel free to give me info. thank you very much. Chloé

  • Anonymous
    January 13, 2010
    Thanks alot for your blog. I have been trying ot get my WCF service with two way SSL work for a long time. Today finally I came across your blog and followed your detailed instructions. It worked. The part I was missing was commenting out the mex endpoint as well as anonymous access. Thanks again! Laleh

  • Anonymous
    January 26, 2010
    The comment has been removed

  • Anonymous
    January 28, 2010
    Hi,       Very good article. Do you have steps to do similar thing in IIS7 on Windows 2008 server.

  • Anonymous
    February 18, 2010
    "The only problem we have noticed that once Anonymous is enabled on IIS, ANY certificate issued by CA that is in trusted authorities store is granted access. Is there a possibility to restrict access to just one specific Cert?" This is the issue we're having as well. Any client cert passed to the service works. How do you lock the service down to a specific cert?

  • Anonymous
    March 03, 2010
    To answer my own question above, it turns out you cannot lock the service down to a specific cert using transport security. You must use message security, specify PeerTrust, and make sure the cert is in the Trusted People store on the server. Hope this helps someone else.

  • Anonymous
    April 07, 2010
    Thanks, very very helpful information keep it up!

  • Anonymous
    January 10, 2011
    The comment has been removed

  • Anonymous
    February 19, 2011
    The article is missing the point. "Certificate mapping" is there to restrict access to those who have the right cert (the one used in mapping). If anybody (with any valid cert) can access the site, your mapping is useless. If you only want 2 way authentication - you dont need cert mapping, just use "require cert" option + ssl. To make mapping work, you have to use a DISABLED account when configuring anonymous access in IIS.

  • Anonymous
    February 28, 2011
    Hi; I am wonder if this is the setup I need for a 2 way trust? I am trying to setup a 2 way HOST-to-HOST SSL certification, or something of the like. It's not really the same old Server -> Client ssl cert setup? I have my SSL certs installed on the server and the hierarchy with the provider (verisign/GoDaddy) is working and have the intermediate certs also configured We wish to send to my vendor my certs for them to install and conversely have them send their certs to us to install on IIS and have a 2 way trust.  I have my vendors certs, what is the procedure for the install/config on my end in IIS? Thanks in advance, Steve.

  • Anonymous
    August 02, 2011
    The comment has been removed

  • Anonymous
    August 29, 2011
    Thanks for the great post! I followed the steps, but I could not get a prompt to select certificate while accessing the service. It got directly accessed. What could be the reason? I want it to prompt for certificate, did I miss anything?

  • Anonymous
    August 29, 2011
    Hi, I am geting this error; PLEASE HELP ME!."The SSL settings for the service 'SslRequireCert' does not match those of the IIS 'Ssl, SslNegotiateCert'

  • Anonymous
    August 29, 2011
    I got this "The private key is not present in the X.509 certificate", any idea why so? I have exported PVX for the certificate. Still gives me this exception on Client Side.

  • Anonymous
    September 20, 2011
    Hi, This is a great article. How can I only use SSL @ Server side? That means i want to host WCF Services under SSL Site but I am not expecting my clients to have the SSL certificate? What Do I have to change for that in my configuration? Thanks

  • Anonymous
    February 21, 2012
    how can i secure my WCF without using certificates simply using user name and password thanks!

  • Anonymous
    October 15, 2012
    how to configure/implement at in code aspx application side