Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#4.0

HTTPS Communication in WCF using Self-sign Certificate

4.78/5 (5 votes)
1 Apr 2013CPOL4 min read 53.4K  
HTTPS Communication in WCF

Introduction

When working with distributed application, securing communication between the client and the service is a very vital issue. Windows Communication Foundation provides the facility of transfer security which is responsible for ensuring the integrity and confidentiality of service messages, and also responsible for providing authentication. Transfer security in WCF is achieved through the use of either transport security or message security. Transport-layer security provides integrity and confidentiality, while message-layer security provides a variety of passes which are not possible with transport security mechanisms. When using transport security, user credentials are transport-dependent, which allows fewer authentication options compared to message security. And each transport protocol has its own way for passing credentials and handling message guard. But SSL is the most common approach for encrypting and signing the contents sent over HTTPS. Here, I will explain how to configure WCF Services and Clients to communicate over HTTPS by using self-signed Certificates.

When I intend to write any technical stuff, my intention always goes to start with a very simple example as well as gives an overview with the necessary things related to it. There is no difference this time as well. So for the purposes of this blog post, I am going to organize it with Self-Signed Certificate Creation, Services and its Configuration, Clients and its Configuration. Please note that I would like to use custom binding for the code examples given here.

Self-Signed Certificate Creation

In Certificate based communication, we need to use two certificates for the client and server to authenticate each other. To make those certificates, I would like to use the “MakeCert.exe” utility with the following arguments:

makecert -pe -ss My -sr LocalMachine -a sha1 -sky exchange -n CN=ServerCertificate

makecert -pe -ss MY -sr LocalMachine -a sha1 -sky exchange -n CN=ClientCerttificate

Image

The complete specification of this is available here.

Now,

First bring up the Microsoft Management Console by launching mmc.exe which allows us to browse the local machine’s cache of certificates.

Image

Next add the Certificates MMC Snap-in and select Computer account.

Image

Navigate to the “Personal” node to see ClientCertificate and ServerCertificate.

Image

It is also required to export the certificates from the certificate store and import the copies of those into the TrustedPeople store so that WCF can find them for validation purposes.

Since I would like to use IIS hosting, we need to configure IIS for https. To do that,

  • Open IIS Manager
  • Select Default Web site and open its property window
  • Click the Edit Binding.

Image

Click Add and select HTTPS and then Select ServerCertificate that you have created earlier.

Image

Okay done. Everything is okay now.

Service and its Configuration

Here, I have used a very simple service which is “Feedback” service. The service contract looks like:

C#
[ServiceContract]
public interface IFeedback
{
   [OperationContract]
   string GiveFeedback(string question);
}

With such a simple contract, the implementation is just straight forward:

C#
public class Feedback : IFeedback
{
    public string GiveFeedback(string question)
    {
        var feedback = question + " : This is very funny stuff";
        return feedback;
    }
} 

The configuration file for this Service is given below:

XML
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="Rashim.RND.WCF.SecureCommunication.WcfService.Feedback" 
      behaviorConfiguration="MyCustomBehavior">
        <endpoint address="" binding="customBinding" 
        contract="Rashim.RND.WCF.SecureCommunication.Interfaces.IFeedback"  
        bindingConfiguration="MyCustomBinding"/>
        <endpoint address="mex" binding="mexHttpsBinding" 
        contract="IMetadataExchange" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyCustomBehavior">
          <serviceMetadata httpsGetEnabled="true" />
          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="PeerTrust" 
              trustedStoreLocation="LocalMachine" />
            </clientCertificate>
            <serviceCertificate findValue="ServerCert" 
            x509FindType="FindBySubjectName" 
            storeLocation="LocalMachine" storeName="My"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <customBinding>
        <binding name="MyCustomBinding" 
        closeTimeout="00:20:00" openTimeout="00:20:00" 
        receiveTimeout="00:20:00" sendTimeout="00:20:00">
          <security authenticationMode="CertificateOverTransport" 
          requireSecurityContextCancellation="true"/>                    
          <httpsTransport/>
        </binding>
      </customBinding>
    </bindings>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="false" />
  </system.serviceModel>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="false" />
    <directoryBrowse enabled="true" />
  </system.webServer>

</configuration> 

To get a better idea about the different sections of this configuration file, I would like to explain it a bit more.

XML
<services>
    <service name="Rashim.RND.WCF.SecureCommunication.WcfService.Feedback"
                     behaviorConfiguration="MyCustomBehavior">
      <endpoint address="" binding="customBinding"
      contract="Rashim.RND.WCF.SecureCommunication.Interfaces.IFeedback"
      bindingConfiguration="MyCustomBinding"/>
      <endpoint address="mex" binding="mexHttpsBinding"
                              contract="IMetadataExchange" />
    </service>
  </services>

In this above section, we see that Custom behavior configuration and custom binding configuration have been used.

The custom behavior section is given below:

XML
<serviceBehaviors>
        <behavior name="MyCustomBehavior">
          <serviceMetadata httpsGetEnabled="true" />
          <serviceCredentials>
            <clientCertificate>
              <authentication certificateValidationMode="PeerTrust" 
              trustedStoreLocation="LocalMachine" />
            </clientCertificate>
            <serviceCertificate findValue="ServerCert" 
            x509FindType="FindBySubjectName" 
            storeLocation="LocalMachine" storeName="My"/>
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>

Here, clientCertificate describes an X.509 certificate which has been used to validate a client to a service. At the same time, serviceCertificate specifies an X.509 certificate that will be used to authenticate the service to clients. There is a detailed explanation about that has been given here [^] [^].

And the custom binding configuration section is:

XML
<bindings>
      <customBinding>
        <binding name="MyCustomBinding" 
        closeTimeout="00:20:00" 
        openTimeout="00:20:00" receiveTimeout="00:20:00" 
        sendTimeout="00:20:00">
          <security authenticationMode="CertificateOverTransport" 
          requireSecurityContextCancellation="true"/>                    
          <httpsTransport/>
        </binding>
      </customBinding>
    </bindings> 

We know that WCF provides several modes by which clients and services verify to each other. We can create binding for these authentication modes through configuration or by code. Here, I have used CertificateOverTransport which means the service is valid using an X.509 certificate at the transport layer. And requireSecurityContextCancellation specifies whether security context should be cancelled and terminated when it is no longer required.

That’s it! Now try to browse https://localhost/Feedback/Feedback.svc and you will get the following page:

Image

Client and its Configuration

Once services have been implemented, the implementation of client is pretty simple. The client code has been given below:

C#
System.Net.ServicePointManager.ServerCertificateValidationCallback += 
            (se, cert, chain, sslerror) => true;
            var channel = new ChannelFactory<IFeedback>("FeedbackEndpoint");
            var client = channel.CreateChannel();

            var input = Console.ReadLine();

            while (input != null && input.ToLower() != "exit")
            {
                var feedback = client.GiveFeedback(input);
                Console.WriteLine(feedback);
                input = Console.ReadLine();
            }             

The code above will trust any security certificate handed back from the server since it bypasses the SSL certificate validation. As the certificate I have used here is a self-signed certificate and it is not signed by a trusted CA, I need to make my own validation logic to check for it.

So the configuration file for the client is:

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <bindings>
      <customBinding>
        <binding name="MyCustomBinding">
          <security authenticationMode="CertificateOverTransport"/>           
          <httpsTransport />
        </binding>
      </customBinding>
    </bindings>
    <behaviors>
      <endpointBehaviors>
        <behavior name="MyCustomBehavior">
          <clientCredentials>
            <clientCertificate findValue="ClientCertificate" 
            storeLocation="LocalMachine" storeName="My" 
            x509FindType="FindBySubjectName" />
            <serviceCertificate>
              <authentication certificateValidationMode="PeerTrust"/>
            </serviceCertificate>
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <client>
      <endpoint address="https://localhost/Feedback/Feedback.svc"
          binding="customBinding" bindingConfiguration="MyCustomBinding"
          contract="Rashim.RND.WCF.SecureCommunication.Interfaces.IFeedback" 
          behaviorConfiguration="MyCustomBehavior" name="FeedbackEndpoint">
        <identity>
          <dns value="ServerCertificate"/>
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>
</configuration> 

That’s it! I think this would help you while you will be working with the Certificate based communication.

Filed under: C#, Codeproject, Technical, WCF
Tagged: C#, HTTPS, SSL Certificate, WCF
Image 8 Image 9 Image 10 Image 11 Image 12 Image 13 Image 14 Image 15

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)