Using transport security on a self-hosted WCF service
I've just spent half a day with my colleague Sérgio to get this thing working, and I've decided to share it with the community.
The
deal was to enable transport security on a basicHttpBinding in a
self-hosted WCF service. I am not going into the service definition
logic because it's not really relevant in this context. Instead I'll
focus on configuration and the steps for achieving transport security
using a service certificate (X.509 certificate).
If you are new on
PKI and the concepts behind digital certificates, you should get some
background info to help you to understand some of these concepts. Check
this topic group on MSDN concerning
Transport Security that will help you to understand the underlying concepts of PKI.
An important point here, is that WCF does not internally enable transport security (SSL).
You can achieve transport security in WCF by introducing some external
artifacts. If you are hosting your service on IIS (which is not the
case in this example), you can use IIS to configure and enable SSL.
There is at least one sample on the Windows SDK that addresses this
scenario.
The other scenario is enabling SSL on a self-hosted service (and this is what this post is about).
The followed example was created using the .NET Framework 3.0 September CTP.
The first step is to create your service logic. The service configuration will be exemplified declaratively on the .config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="bindingWithTransportSecurity">
<security mode="Transport">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="myServiceBehavior">
<!--
if you remove this element it will also works, this is not necessary
for the SSL. SSL is achieved through the HttpCfg.exe as we'll see
bellow -->
<serviceCredentials>
<serviceCertificate
findValue="CN=MYSERVER"
storeLocation="LocalMachine"
x509FindType="FindBySubjectDistinguishedName"
storeName="My" />
</serviceCredentials>
<!-- publish service metadata from a HTTPS GET request ex: https://MYSERVER:8888/demo?wsdl -->
<serviceMetadata httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="myServiceBehavior" name="Demo.HelloWorldService">
<endpoint
address="https://MYSERVER:8888/demo"
binding="basicHttpBinding"
bindingConfiguration="bindingWithTransportSecurity"
contract="Demo.IHelloWorldService" />
<host>
<baseAddresses>
<add baseAddress="https://MYSERVER:8888/demo" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
This
file associated to your service contains the configuration data to
enable transport security to your service. You now need to issue the
proper certificate using a CA or makecert (for testing purposes). If
you are using a Microsoft Windows CA you can request the digital
certificate by choosing:
Advanced Certificate Request from
the CA the web application and provide the hostname as the name
(subject name) for your digital certificate. In this case, it will be
MYSERVER. Also, you must request the certificate type as
Server Authentication, indicate you want to store the certificate on the
Local Computer Store and the hash being a
SHA1 hash type.
Then,
go to the Certification Authority console and issue the certificate
that should be in pending. After doing this, go back to the CA web
application, and install the certificate on your computer. Check if the
certificate was added to the Local Computer store, under
Personal\Certificates.
Now you are almost done. Remember that
WCF does not internally enable transport security. You have to
configure this by yourself. To achieve this you will require the
HttpCfg.exe tool. This is part of Windows XP SP2 Support Tools and is
available for download
here. (This tool is available by default on Windows 2003).
If the HttpCfg.exe is installed use it to configure a port with an X.509 certificate:
HttpCfg.exe set ssl -i 0.0.0.0:8888 -h e561943dac9441e1ecaafb064e86b047672adb2d -n LOCAL_MACHINE -c MY
where 0.0.0.0:8888, is the IP Address and the port for your
certificate and the e561943dac9441e1ecaafb064e86b047672adb2d is the
thumbprint of the certificate (the SHA1 hash) that you can obtain on
the certificate Details tab in the certificate (when copying it remember to remove the spaces on it).
And that should be done. You can now run your service using transport security on a self-hosted WCF service.