kfoster
kfoster

Reputation: 1653

How do I setup Client and Server Certificates for WCF Transport Security?

My scenario: I have a public facing web app hosted on Amazon EC2 servers. I have a self-hosted database server behind a firewall. I have self-hosted Web Service servers with a web service for data access. I want to allow only applications I approve (my own living in the cloud) to access the services and I don't want any data passed in clear-text.

From what I can tell reading all the disjointed and maddeningly obfuscated MSDN articles, Stackoverflow threads, Code Project articles, and other blogs. The type of security I need is: Transport Security mode with Certificate clientCredentialType, using wsHttpBinding. First question, am I right in assuming that? Will that give me enough security? This isn't B2B or anything like that. It is, however, cross domain and I just want to ensure I can trust the caller. My service is running in an AppPool owned by a specific user so I can access the DB with integrated security. I need to make sure only callers to my service that I approve get in. I don't need to encrypt the message anymore than SSL already does I don't believe.

All the scenarios possible make it very very difficult to know if this is what I want. But assuming it is the next question is how do I set up the Certs? I currently have a Certificate on the server, and I can only access with Https. (security mode="Transport", clientCredentialType="None"). But for the life of me I can't figure out what I need to do to change clientCredentialType to Certificate and get it to work.

All development articles I read say that Cert setup is an Admin tool and beyond the scope of the article. Well, the WCF stuff is straightforward, it's exactly the friggin cert stuff I need help with, and there are no useful articles that I've found yet. Those that come close show how to do it with makecert.exe and say in production it will be different, but then don't say how to do it in production.

I'm sure my frustration level is showing, sorry about that. But it really makes no sense that there isn't a clear description on how to do what seems like a pretty common security scenario in WCF.

Any and all help appreciated, Ken

Upvotes: 3

Views: 2963

Answers (1)

cchdev
cchdev

Reputation: 511

Short Answer

The type of security I need is: Transport Security mode with Certificate clientCredentialType, using wsHttpBinding. First question, am I right in assuming that?

Yes. Message security would also work assuming you do not use WCF streaming features, but with transport security you can benefit hardware acceleration.

how do I set up the Certs?

Please see the detailed answer below.

What do I give the client from the server and where does it go? If I have several clients (a web farm) do I have to have a different client cert for all of them, or can they share one cert that my server accepts?

You need 3 certificates :

  • a client certificate (the same for all clients).
  • a server certificate.
  • a certificate authority (CA) certificate, by whom the client and server certificates were issued.

The client needs:

  • The client certificate installed in the Personal Certificates store.
  • The CA certificate installed in the Trusted Root Certification Authorities store.

What do I give the server from the client and where does it go?

The server needs:

  • The server certificate installed in the Personal Certificates store.
  • The CA certificate installed in the Trusted Root Certification Authorities store.
  • The client certificate installed in the Trusted People store.

Detailed Answer

In this scenario (communication between web farm and self hosted web services), you own both client and server machines. There is no need for third-party issued certificates (you trust yourself, right?). Which means you can safely use home-made certificates.

Here is a quick guide I hope will help you (or someone else), achieve this. If you already own certificates as your question suggests, feel free to skip step I. Furthermore, you may already have bought third-party issued certificates, in that case the root certificate authority (VeriSign, Microsoft, etc) certificate may already be installed on your client and server machines.

I. Create certificates

As explained in this msdn article, use makecert to generate 3 certificates:

  1. A root certificate authority certificate, let's call it MyRootCA, and its revocation list.
  2. A server SSL certificate. The name must be the domain name your web farm clients will use to call the web services. For example, if your clients use the following url: https://mywebserver.myprivatedomain.com/service1.svc, then your certificate CN (Common Name) will be mywebserver.myprivatedomain.com.
  3. A client X.509 certificate, let's call it MyAmazonClient.

Here is a simple batch that achieves those 3 steps:

REM 1: MyRootCA
makecert -n "CN=MyRootCA" -r -sv "MyRootCA.pvk" "MyRootCA.cer"
makecert -crl -n "CN=MyRootCA" -r -sv "MyRootCA.pvk" "MyRootCA.crl"

REM 2: mywebserver.myprivatedomain.com
makecert -sk "mywebserver.myprivatedomain.com" -iv "MyRootCA.pvk" -n "CN=mywebserver.myprivatedomain.com" -ic "MyRootCA.cer" -sr LocalMachine -ss My -sky exchange -pe

REM 3: MyAmazonClient
makecert -sk "MyAmazonClient" -iv "MyRootCA.pvk" -n "CN=MyAmazonClient" -ic "MyRootCA.cer" -sr LocalMachine -ss My -sky signature -pe

This batch will create 3 files in the current folder:

  • MyRootCA.cer: contains the public key of the root CA certificate.
  • MyRootCA.crl: contains the certificate revocation list.
  • MyRootCA.pvk: contains the private key of the root CA certificate.

The 2 other certificates (client and server) are installed in local computer certificate store.

Using the Certificates MMC Snap-in, export them into .pfx files:

  • Locate LocalMachine > My > Certificates.
  • Right click MyAmazonClient > All Tasks > Export.
  • Right click mywebserver.myprivatedomain.com > All Tasks > Export.

II. Install server certificates

On your server machine (the one exposing the web services), copy the following files:

  • MyRootCA.cer
  • MyRootCA.crl
  • MyAmazonClient.pfx
  • mywebserver.myprivatedomain.com.pfx

Using the Certificates MMC Snap-in on the server machine, install the certificates in the following locations:

  • MyRootCA.cer and MyRootCA.crl into Local Computer > Trusted Root Certification Authorities > Certificates
  • MyAmazonClient.pfx into Local Computer > Trusted People > Certificates
  • mywebserver.myprivatedomain.com.pfx into Local Computer > Personal > Certificates

Grant your IIS AppPool access to the private key of the mywebserver.myprivatedomain.com certificate. In MMC Certificates Snap-in, right click mywebserver.myprivatedomain.com > All Tasks > Manage Private Keys... Then add the identity your AppPool is running with. Note than when using ApplicationPoolIdentity (by default), identity name is IIS AppPool\YourAppPoolNameHere.

III. Configure IIS to support SSL

Using IIS Manager, locate your website and add an https binding with your mywebserver.myprivatedomain.com certificate. See Step 4: Configure Your Temporary Service Certificate in IIS to Support SSL.

IV. Configure the services (web.config)

  <system.serviceModel>
    <protocolMapping>
      <add scheme="https" binding="wsHttpBinding" />
    </protocolMapping>
    <bindings>
      <wsHttpBinding>
        <!-- configure wsHttp binding with Transport security mode and clientCredentialType as Certificate -->
        <binding>
          <security mode="Transport">
            <transport clientCredentialType="Certificate"/>            
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>

V. Install client certificates

On each client machine (web farm), copy the following files:

  • MyRootCA.cer
  • MyRootCA.crl
  • MyAmazonClient.pfx

Using the Certificates MMC Snap-in on the client machines, install the certificates in the following locations:

  • MyRootCA.cer and MyRootCA.crl into Local Computer > Trusted Root Certification Authorities > Certificates
  • MyAmazonClient.pfx into Local Computer > Personal > Certificates

Grant your IIS AppPool access to the private key of the MyAmazonClient certificate (same steps as II).

VI. Configure the clients (web.config)

  <system.serviceModel>
    <client>
      <!-- this endpoint has an https: address -->
      <endpoint address="https://mywebserver.myprivatedomain.com/service1.svc" 
                behaviorConfiguration="endpointCredentialBehavior"
                binding="wsHttpBinding" 
                bindingConfiguration="Binding1" 
                contract="MyWebApp.IServiceContract"/>
    </client>
    <behaviors>
      <endpointBehaviors>
        <behavior name="endpointCredentialBehavior">
          <clientCredentials>
            <clientCertificate findValue="MyAmazonClient"
                               storeLocation="LocalMachine"
                               storeName="My"
                               x509FindType="FindBySubjectName" />
          </clientCredentials>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <bindings>
      <wsHttpBinding>
        <!-- configure wsHttpbinding with Transport security mode
                   and clientCredentialType as Certificate -->
        <binding name="Binding1">
          <security mode="Transport">
            <transport clientCredentialType="Certificate"/>
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>

And that's it.

Upvotes: 3

Related Questions