How To – Use Certificate Authentication and Message Security in WCF calling from Windows Forms

- J.D. Meier, Jason Taylor, Prashant Bansode, Carlos Farre, Madhu Sundararajan, Steve Gregersen

Applies to

  • Windows Communication Foundation 3.5
  • Microsoft® Visual Studio 2008

Summary

This How To article walks you through the process of using client certificate and message security to authenticate your users. The article shows you how to create and install client and service certificates during development, configure WCF service and client to use the respective certificates, and test the service with a sample WCF client.

Contents

  • Objectives
  • Overview
  • Summary of Steps
  • Step 1 – Create a Sample WCF Service
  • Step 2 – Configure wsHttpBinding with Certificate Authentication and Message Security
  • Step 3 – Create and Install Certificates for Service and Client
  • Step 4 – Copy the Certificates to the Trusted People Store
  • Step 5 – Configure the Service Certificate for WCF
  • Step 6 – Create a Test Client
  • Step 7 – Add WCF Service Reference to the Client
  • Step 8 – Export the Client Certificate with Private Key
  • Step 9 – Import the Client Certificate with Private Key to the Trusted People Store
  • Step 10 – Configure the Client Certificate for WCF
  • Step 11 – Test the Client and WCF Service
  • Additional Resources

Objectives

  • Learn how to create and use a temporary certificate for authentication and message security.
  • Learn where to store the temporary certificate.
  • Learn how to troubleshoot common errors related to temporary certificates, authentication and message security in WCF.

Overview

When developing a WCF service that uses X.509 certificates to provide client authentication and message security, it is necessary to work with temporary certificates. This is because production certificates are expensive and may not be readily available. There are two options for specifying trust on a certificate:
  • Peer trust – Validates the certificate directly.
  • Chain trust – Validates the certificate against the issuer of a certificate known as a root authority.

This How To article discusses the chain trust option because it is the most commonly used approach in Business-to-Business (B2B) scenarios.

To use chain trust validation during development time, you create a self-signed root certificate authority (CA) and place it in the Trusted Root Certification Authority store of the client and service machines. The certificate used by WCF Client for client authentication and WCF Service for Service authentication and message protection, is then created and signed by the root self-signed certificate and installed in the LocalMachine store.

You will use makecert.exe to create a certificate to act as your root certificate authority (CA). You will then use your root CA certificate to sign additional certificates for your WCF service and client. Finally, you will configure WCF client and service to use your temporary certificate.

Summary of Steps

  • Step 1 – Create a Sample WCF Service
  • Step 2 – Configure wsHttpBinding with Certificate Authentication and Message Security
  • Step 3 – Create and Install a Service Certificate
  • Step 4 – Configure the Service Certificate for WCF Service
  • Step 5 – Create a Test Client
  • Step 6 – Add WCF Service Reference to the Client
  • Step 7 – Create and Install the Client Certificate for Authentication
  • Step 8 – Configure the Client Certificate in WCF Client Application
  • Step 9 – Test the Client and WCF Service

Step 1 – Create a Sample WCF Service

In this step you will create a WCF service in Visual Studio.
  1. In the Visual Studio, from the menu select File -> New Web Site
  2. In the Templates section select WCF Service. Make sure that the Location is set to Http and specify the virtual directory to be created in the Path (e.g.** http://localhost/WCFTestService).
  3. Click Ok on the New Web Site dialog box; this will create a virtual directory, and a sample WCF service.
  4. Browse to your WCF Service (i.e. http://localhost/WCFTestService/Service.svc). You should see details of your WCF Service.

Step 2 – Configure wsHttpBinding with Certificate Authentication and Message Security

In this step you will configure the WCF service to use Certificate authentication and message security.
  1. Right click on the Web.config file of the WCF Service and choose the option, Edit WCF Configuration...
  2. In the configuration editor, in the configuration section, expand Service and then expand Endpoints
  3. Select the first node Empty Name. Set the name attribute to wsHttpEndpoint. By default the name will be empty, as it’s an optional attribute.
  4. Click the Identity tab and delete the Dns attribute value.
  5. In the configuration editor, select the Bindings folder.
  6. In the Bindings section choose New Binding Configuration.
  7. In the Create a New Binding dialog box, select wsHttpBinding.
  8. Click Ok button.
  9. Set the Name of the binding configuration to some logical and recognizable name, for example wsHttpEndpointBinding.
  10. Click the Security tab.
  11. Make sure the Mode attribute is set to Message, which is the default setting.
  12. Set the MessageClientCredentialType to Certificate option from the drop down.
  13. Select the wsHttpEndpoint node in the configuration section.
  14. Set the BindingConfiguration attribute to wsHttpEndpointBinding from the drop down. This associates the binding configuration setting with the binding.
  15. On the configuration editor dialog, got to File menu and select Save.
  16. In Visual Studio, open your configuration and comment out the identity element. It should look as follows:
<!--<identity>
  <dns value="" />
</identity>-->
  1. In Visual Studio, verify your configuration. The configuration should look as follows:
…
<bindings>
  <wsHttpBinding>
    <binding *name="wsHttpEndpointBinding"*>
      <security>
        <message *clientCredentialType="Certificate"* />
      </security>
    </binding>
  </wsHttpBinding>
</bindings>
<services>
  <service behaviorConfiguration="ServiceBehavior" name="Service">
    <endpoint address="" binding="wsHttpBinding"
      *bindingConfiguration="wsHttpEndpointBinding"*
      *name="wsHttpEndpoint"* contract="IService">
      <!--<identity>
        <dns value="" />
      </identity>-->
    </endpoint>
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>
…

Step 3 – Create and Install a Service Certificate

In this step, you create a temporary Service Certificate and install it in the local store. This certificate will be used for service authentication and to encrypt the message, protecting any other sensitive data..

Creating and installing the certificate is outside the scope of this How To article. For detailed steps on how to do this, see How To - Create and Install Temporary Certificates in WCF for Message Security During Development

Note:
  • If you are running on Windows XP, give the certificate permissions for the ASPNET identity instead of the NT Authority\Network Service identity because the IIS process runs under the ASPNET account in Windows XP.
  • Temp certificate should be used for development and testing purposes only. For actual production deployment, you will need to get a valid certificate from a certificate authority (CA).

Step 4 – Configure the Service Certificate for WCF Service

In this step you will configure WCF to use the temporary certificate you created in the previous step.
  1. In the Configuration Editor, expand the Advanced node, then expand the ServiceBehaviors and ServiceBehavior node.
  2. Click the Add button.
  3. In the Service Behavior Element Extensions dialog box, select serviceCredentials option and click Add button.
  4. Expand the serviceCredentials node and select the serviceCertificate node.
  5. Set the FindValue attribute to the name of the service certificate that you have created. For example, "CN=tempCertServer".
  6. Leave the default settings for StoreLocation and StoreName as is..
  7. Select the clientCertificate node, set the RevocationMode to NoCheck option from the drop down.
Important: The revocation mode is set to NoCheck as we are using the temporary certificates created using makecert utlity. In production environment you should not change the default Online option.
  1. On the configuration editor dialog, go to the File menu and select Save.
  2. In Visual Studio, verify your configuration. The configuration should look as follows.
...
<behaviors>
  <serviceBehaviors>
    <behavior name="ServiceBehavior">
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="false" />
      <serviceCredentials>
        <clientCertificate>
          <authentication *revocationMode="NoCheck"* />
        </clientCertificate>
        <serviceCertificate *findValue="CN=tempCertServer"* />
      </serviceCredentials>
    </behavior>
  </serviceBehaviors>
</behaviors>
...

Step 5 – Create a Test Client

In this step, create a Windows Form application to test WCF Service.
  1. Right-click your Solution, click Add and then click New Project.
  2. In the Add New Project dialog box, select Windows Forms Application from the Templates section.
  3. In the Name field, type Test Client and click Ok button.

Step 6 – Add WCF Service Reference to the Client

In this step, you add a reference to your WCF Service.
  1. Right-click your Client project and select Add Service Reference.
  2. In the Add Service Reference dialog box, set the url to your WCF Service, (e.g. http://localhost/WCFTestService/Service.svc) and click the Go button.
  3. In the Web reference name field name, change ServiceReference1 to WCFTestService
  4. Click Add Reference. In your Client project, a reference to WCFTestService should appear beneath Web References.

Step 7 – Create and Install the Client Certificate for Authentication

In this step, you create a temporary Client Certificate, using the Root CA created in Step 3 above, and install it in the local store. This certificate will be used for client authentication and to encrypt the message, protecting any other sensitive data.
  1. Copy the root CA certificate (RootCATest.cer) and privatekeyfile (RootCATest.pvk) to the client machine.
  2. Open a Visual Studio command prompt and browse to the location where you have copied the root CA certificate and privatekeyfile.
  3. Run following command for creating a certificate signed by the root CA certificate:

makecert -sk MyKeyName -iv RootCATest.pvk -n "CN=tempCert" -ic RootCATest.cer -sr localmachine -ss my -sky exchange -pe tempCert.cer
  1. In the Enter Private Key Password dialog box, enter the password for the root CA privatekeyfile specified in Step 3, and then click OK.

For more information and detailed steps, see How To - Create and Install Temporary Certificates in WCF for Message Security During Development.

Step 8 – Configure the Client Certificate in WCF Client Application

In this step you will configure the WCF client to the temporary certificate you created in the previous step.
  1. Right click the App.config file in your test client and select Edit WCF Configuration.
  2. In the configuration editor, expand the Advanced node, select Endpoint Behaviors, and select New Endpoint Behavior Configuration
  3. Click the Add button.
  4. In the Adding Behavior Element Extension Sections dialog box, select clientCredentials and click Add button.
  5. Expand the clientCredentials node and then expand the serviceCertificate node and then select authentication below it.
  6. Set the CertificateValidationMode to PeerTrust option from the drop down.
  7. Select the clientCertificate node, set the FindValue attribute to the subject name of the client certificate that you created and installed in Step 7. For example, "CN=tempCertClient".
  8. Set the StoreLocation attribute to the LocalMachine option from the drop down.
  9. Expand the clientCredentials node, expand the serviceCertificate node, and then select authentication below it.
  10. Set the RevocationMode attribute to NoCheck by choosing this option from the drop-down list.
Important: The revocation mode is set to NoCheck as we are using the temporary certificates created using makecert utlity. In production environment you should not change the default Online option.
  1. In the configuration editor, expand the Client node and then expand the Endpoints node and select the WsHttpEndpoint node.
  2. Set the BehaviorConfiguration attribute to NewBehavior, choosing from the drop down, this is the endpoint behavior you just created.
  3. On the configuration editor dialog, go to the File menu and select Save.
  4. In Visual Studio, verify your configuration. The configuration should look as follows.
<system.serviceModel>
    <behaviors>
        <endpointBehaviors>
            <behavior *name="NewBehavior"*>
                <clientCredentials>
                    <clientCertificate *findValue="CN=tempCertClient" storeLocation="LocalMachine"* />
                </clientCredentials>
                <serviceCertificate>
                  <authentication *revocationMode="NoCheck"* />
                </serviceCertificate>
            </behavior>
        </endpointBehaviors>
    </behaviors>
    ...
    <client>
        <endpoint address="http://<<service address>>"
            *behaviorConfiguration="NewBehavior"* binding="wsHttpBinding"
            bindingConfiguration="wsHttpEnpoint1" contract="ServiceReference1.IService"
            name="wsHttpEnpoint">
            <identity>
                <certificate encodedValue="<<Encode Value>>" />
            </identity>
        </endpoint>
    </client>
</system.serviceModel>

Step 9 – Test the Client and WCF Service

In this step you access the WCF Service as and pass the user credentials and make sure the username authentication works.
  1. In your Client project, drag a Button control to your Form.
  2. Double-click the Button control to show the code behind.
  3. Create an instance of the proxy, and call the GetData operation of your WCF Service. The code should look as follows:
private void button1_Click(object sender, EventArgs e)
{
      WCFTestService.ServiceClient myService = new
                    WCFTestService.ServiceClient();
      MessageBox.Show(myService.GetData(123));
      myService.Close();
}
  1. Right click on the Client project and select Set as Startup Project
  2. Run the Client application using F5 or Ctrl+F5, when you click the Button on the form it should display a message “You entered: 123

Additional Resources

Contributors and Reviewers

  • External Contributors and Reviewers:
  • Microsoft Consulting Services and PSS Contributors and Reviewers:
  • Test team: Rohit Sharma, Chaitanya Bijwe, Parameswaran Vaideeswaran.
  • Edit team: Dennis Rea.
  • SEO team: Rob Boucher.

Last edited Apr 30, 2008 at 9:58 PM by prashantbansode, version 1

Comments

sanojtomar Dec 27, 2013 at 11:15 AM 
Hi,

I was also getting the error below:


Then I again created certificates from the scartch. PLease folllow steps mentioned in below link
http://www.digitallycreated.net/Blog/38/using-makecert-to-create-certificates-for-development

yazidarezki,
Please correct certificate name in config file to which you created.

sedatiko Mar 1, 2012 at 10:00 PM 
How do you call this service from a non .net client???

jsoler Jul 6, 2010 at 7:33 PM 
I have this error The caller was not authenticated by the service.

This is configuration in client

<client>
<endpoint address="http://localhost:49981/AKTWCFService/Service.svc"
behaviorConfiguration="NewBehavior" binding="wsHttpBinding"
bindingConfiguration="wsHttpEndpoint" contract="ServiceReference1.IService"
name="wsHttpEndpoint">
<identity>
<dns value="" />
<certificate encodedValue="" />
<certificateReference findValue="" />
</identity>
</endpoint>
</client>

In this line no appear <certificate encodedValue="" />

akleinwaechter Aug 24, 2009 at 3:36 PM 
Great article. The certificate based message security works great.
But I have one big problem:
If on clientside something is wrong with the installed certificates or the client certificate is missing the service is going to faulted state immediately. The error is thrown before my custom code is executed. The service has to be restarted manually on the server. Is there some parameter in the configuration that prevents this behaviour?

Best regards
Alex form Berlin, Germany

jjacobs Aug 12, 2008 at 6:34 PM 
There is a mistake in the configuration of the "endPointBehavior" in Step 8. The "serviceCertificate" node should be a child node of the "clientCredentials" node as shown below, and not a child node of the "endPointBehavior"

<endpointBehaviors>
<behavior *name="NewBehavior"*>
<clientCredentials>
<clientCertificate *findValue="CN=tempCertClient" storeLocation="LocalMachine"* />
<serviceCertificate>
<authentication *revocationMode="NoCheck"* />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>

yazidarezki May 19, 2008 at 4:59 PM 
Hello,

I got step 4 and then I tried to see whether my host is running properly and I get the following error:

Cannot find the X.509 certificate using the following search criteria: StoreName 'My', StoreLocation 'LocalMachine', FindType 'FindBySubjectDistinguishedName', FindValue 'CN=tempCertServer'

This is what my config look like:

{{
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="wsHttpEndpointBinding">
<security>
<message clientCredentialType="Certificate" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="Service">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding"
name="wsHttpEndpoint" contract="IService">
<identity>
<dns value="" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<clientCertificate>
<authentication revocationMode="NoCheck" />
</clientCertificate>
<serviceCertificate findValue="CN=tempCertServer" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

}}

Any pointers to what I have done wrong will be very helpful.

TIA
Yaz