Welcome to GASP Sign in | Join | Help

Using transport security on a self-hosted WCF service with client credential - certificate

If you read my previous post concerning Transport Security on a Self-Hosted WCF service, you may realize that I was using a digital certificate (X.509) on a basicHttpBinding to encrypt our channel, but with no client authentication. WCF supports several types of client authentication: Basic, Digest, NTLM, Windows and Certificate. I'll focus this post on a client authentication, or if you want, Transport Client Credential: Certificate.

With transport security settled to certificate and a client credential type as certificate were are able to mutually authenticate the server to the client (the SSL connection) and the client to the server (through the client credential).

The first thing to do is to enable transport security. I'll not go on this, because my previous post discusses exactly this, check it out.

Assuming that you have already transport security running ok, you will need to add a few more information into your configuration file:

 

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <system.serviceModel>

 

        <bindings>

            <basicHttpBinding>

                <binding name="bindingWithTransportSecurity">

                    <security mode="Transport" >      

                        <transport clientCredentialType="Certificate" proxyCredentialType="None" />

                    </security>

                </binding>

            </basicHttpBinding>

        </bindings>

 

        <behaviors>

            <serviceBehaviors>

                <behavior name="myServiceBehavior">

                    <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>


The thing here, is to define the client credential type has shown in bold in the server config file. On the client side, your client configuration file must be compliant with the server configuration. The client configuration follows:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <system.serviceModel>

        <behaviors>

           <endpointBehaviors>

                <behavior name="clientBehavior">

                    <clientCredentials>

                        <clientCertificate

                            findValue="Abel Eduardo Pereira"

                            storeLocation="CurrentUser"

                            x509FindType="FindBySubjectName"

                            storeName="My" />

                    </clientCredentials>

                </behavior>

            </endpointBehaviors>

        </behaviors>

        <bindings>

            <basicHttpBinding>

                <binding name="basicHttpClientBinding">

                    <security mode="Transport">

                        <transport clientCredentialType="Certificate" proxyCredentialType="None" realm="" />

                    </security>

                </binding>

            </basicHttpBinding>

        </bindings>

        <client>

            <endpoint

                address="https://sdev44001:8888/demo

                binding="basicHttpBinding"

                bindingConfiguration="basicHttpClientBinding"

                contract="Demo.Proxy.IHelloWorldService"

                behaviorConfiguration="clientBehavior"/>

        </client>

    </system.serviceModel>

</configuration>


At bold, you can find the relevant parts in the client configuration file. The first bolded part, specifies the certificate that will be used for client authentication. This certificate was generated as being a Client Authentication type certificate from the Certificate Authority.
The second bolded part indicates that we will be using a digital certificate as the client credential.

This is all you have to do on your client and server configuration files. However, not enough to put working.
The next step is to reconfigure the server certificate binding to the port to allow client certificates, enabling mutual authentication. Assuming that you have read and tried to do what's in my previous post, you first need to clear the configuration you done with the HttpCfg.exe tool:


C:\Program Files\Support Tools>httpcfg delete ssl -i 0.0.0.0:8888
HttpDeleteServiceConfiguration completed with 0.


The previous command removes the certificate binding to the IP 0.0.0.0 (0.0.0.0 represents the machine address, so it will bind to every IP addresses your machine has)  and port 8888 you had previously configured. You should ignore this command if you haven't done any IP:Port - certificate binding.

Now, you need to configure to enable mutual authentication:


C:\Program Files\Support Tools>httpcfg set ssl -i 0.0.0.0:8888 -h e561943dac9441e1ecaafb064e86b047672adb2d -f 2 -m 1
HttpSetServiceConfiguration completed with 0.


In the blue part, we define the IP & port to which we want to bind your certificate used to enable transport security.
In the red part, we indicate the certificate being used to enable transport security. We specify the certificate by its SHA1 hash. Once again, check the previous port for further details.
In the green part, we indicate we want to negociate the client certificate. This is the key point that enables the client credential to be accepted from the server.
Finally, in the orange part, we specify the certificate check mode. In this case, we are specifying that the client certificate will not be verified for revogation (something you don't want to do in a production environment).

Now we are almost done. Just a few check ups and we are ready to hit F5. You will mainly need this if you don't have a Certificate Authority available or if your certificates are issued from the makecert.exe tool.

Your client has to trust the server certificate (the certificate used enabling transport security, - SSL). Yet, it needs the public key of the server certificate.
If you don't have a Certificate Authority that can tell you  whether the server certificate is trustable or not you should add the root certificate (that makes part of the server certificate) into the Local Computer | Trusted Root Certificate Authorities. Also, you need to install the server certificate public key on the client.

You can install the server certificate public key on the client, by exporting the server certificate to a file:










Now, go to the client and import the server certificate into Current User store | Personal.
Now import the root certificate into Current User store | Trusted Root Certification Authorities using the same procedure:




What you have done so far was to give the server's certificate (containing the public key) to the client and made the client trust this certificate. This should only be necessary if you don't have a certificate authority in place.
The next step is to make the client certificate trustable by the server. You need to execute the inverse procedure to allow the server to trust the client.

And now, the good part: run your service. Invoke a service operation from the client, and check the 


OperationContext.Current.ServiceSecurityContext.PrimaryIdentity


The PrimaryIdentity should contain the client identity based on the client certificate.
Published Saturday, January 20, 2007 2:34 AM by abel.pereira
Filed under:

Comments

No Comments

Anonymous comments are disabled