3

I'm trying to understand the process of transport security authentication, based on certificates. Suppose I'm making a service with the following config with https opened on 8732 port:

<wsHttpBinding>
    <binding name="SecurityTest">
        <security mode="Transport">
            <transport clientCredentialType="Certificate"/>
        </security>
    </binding>
</wsHttpBinding>

<service name="MyNamespace.MyService">
    <host>
        <baseAddresses>
            <add baseAddress="https://localhost:8732/MyService/" />
        </baseAddresses>
    </host>
    <endpoint 
        address="" 
        binding="wsHttpBinding" bindingConfiguration="SecurityTest"
        contract="MyNamespace.IContract" >
    </endpoint>      
</service>

Then I create a self-signed certificate for Root Authority so that I could create new certificates:

makecert -n "CN=MyAuthority" -r -sv MyAuthority.pvk MyAuthority.cer -sky exchange

Then I add my MyAuthority.cer to the local machine "Root" cataloge. After this I create another certificate using my MyAuthority certificate and place it in local machine's "My" catalog:

makecert -sky exchange -sk local -iv MyAuthority.pvk -n "CN=local" -ic MyAuthority.cer local.cer -sr Localmachine -ss My

Then I use netsh to bind my local.cer certificate to 8732 port:

netsh http add sslcert ipport=0.0.0.0:8732 certhash=02b751d7f71423c27141c9c385fc3d3976 d7 aa b5 appid={C4BFC5DC-2636-495B-9803-8DD8257C92C3} 

The server service side is done, and it starts and works. Now I create a client:

<bindings>
    <wsHttpBinding>
        <binding name="SecurityTest" >
            <security mode="Transport">
                <transport clientCredentialType="Certificate"  />
            </security>
        </binding>
    </wsHttpBinding>
</bindings>
<client>
    <endpoint name="testPoint"
        address="https://localhost:8732/MyService/" 
        binding="wsHttpBinding" bindingConfiguration="SecurityTest"  
        behaviorConfiguration="ep" 
        contract="MyNamespace.IContract">
    </endpoint>
</client>
<behaviors>
    <endpointBehaviors>
        <behavior name="ep" >
            <clientCredentials>
                <clientCertificate findValue="local" 
                       storeLocation="CurrentUser" storeName="My" 
                       x509FindType="FindBySubjectName" />
            </clientCredentials>
        </behavior>
    </endpointBehaviors>
</behaviors>

When I start it and consume the service method, I get an error:

MessageSecurityException: The HTTP request was forbidden with client authentication scheme 'Anonymous'" when accessing credential secured WCF service from remote computer

I what to ask if I understand everything well in this scheme, and maybe to get advice, how to solve this error.

  1. Does my service uses local.cer to encrypt messages on transport level?

  2. Do I have to add MyAuthority.cer to Trusted published catalog on each client machine in order my clients could decrypt the messages without creating personal validation handlers?

  3. Does my client in current example uses the local.cer as his credentials, and this certificate would be send to the service side?

  4. How does server side handles the client certificate? Does it check if it was signed by MyAuthority.cer or it checks it with the ssl certificate? How I can see what the certificate is checked with?

  5. Why do I get the error?

Thanks in advance

Reg Edit
  • 6,719
  • 1
  • 35
  • 46
Alex
  • 8,827
  • 3
  • 42
  • 58

1 Answers1

3

1). Does my service uses local.cer to encrypt messages on transport level?

Yes, it does.

2). Do I have to add MyAuthority.cer to Trusted published catalog on each client machine in order my clients could decrypt the messages without creating personal Validation handlers?

Yes, since you are using a self-signed certificate (signed by an authority/CA you created) -- the clients would need to either trust the authority/CA or you would need to write code/configuration on the client side for an "exception".

3). Does my client in current example uses the local.cer as his credentials, and this certificate would be send to the service side?

It may be OK but you shouldn't use the same certificate for both client and server -- you should use a different certificate for the client. Currently, you are instructing it to use the following certificate, per your configuration:

<clientCertificate findValue="localhost" storeLocation="CurrentUser" storeName="My" x509FindType="FindBySubjectName" />

So if you have a certificate with subject name = "localhost" in your CurrentUser/My store, and the identity running the client program can access it (and its private key), it will be presented to the server as a client certificate.

4). How does server side handles the client certificate? Does it check if it was signed by MyAuthority.cer or it checks it with the ssl certificate? How I can see what the certificate is checked with?

The Framework on the server side checks that the client certificate presented is valid and trusted, that is all. If a client presents a certificate signed by e.g. VeriSign and you have the VeriSign CAs in your Machine/Trusted CAs store, that would be considered valid client certificate. If you want to limit the accepted certificates to only those signed by a specific CA, you would need to add additional code for that (or remove all the other trusted CAs from the store).

5). Why do I get the error?

There are a few reasons you could see that (rather cryptic) error message. First off, do you have a certificate in your store matching what is specified in item 3?

mikey
  • 5,090
  • 3
  • 24
  • 27
  • Thank you for a great answer. Suppose I will mark it as correct :) I'm preparing to 70-513, and these certificates are some hell. They behave differently on localhost, domain and internet. IIS hosting gives new troubles. So I came to question, if I myself understand everything right. This example I used in a single computer (which is in domain - suppose it can influence somehow). As for point 3 - both server ssl and client are using the same certificate local.cer (there was a mistake, which I've edited: changed localhost to local in client config) which is in LOCALMACHINE MY cataloge. – Alex Aug 09 '13 at 18:19
  • 1
    Another thing that I should note is this -- The certificate that you set up on the server should have a "Common Name"/"CN" that matches the URL you'd use to access the service. For example if you're accessing the service via https://localhost/ then the common name would be "localhost". If you're accessing it via https://www.google.com then the common name should be "www.google.com" etc. There are some exceptions to this, like wildcard certificates but they don't apply in your proof-of-concept case here. – mikey Aug 09 '13 at 19:20
  • This is a pretty decent resource describing what you're trying to do. The trick is to make certain that your certificates are trusted and that the private key is accessible (this is especially important for the client presenting the client certificate) -- you can test the server by loading the URL in the browser and looking for warnings/errors. http://msdn.microsoft.com/en-us/library/ms731074.aspx – mikey Aug 09 '13 at 19:30
  • Hi @mikey: Can you be more specific with what you mean by custom code? – Matthias Jan 22 '14 at 14:32
  • @Matthias - One way that I further refine which certificates I accept and which I deny is to examine the certificate presented by the client (I examine it on the server side). Here is a link to some of the properties: http://msdn.microsoft.com/en-us/library/system.web.httprequest.clientcertificate%28v=vs.110%29.aspx . One configuration that I've used is to set up the OS/IIS to trust all certificates from a given source/CA (the "first gate"), but then I examine each cert in my app logic (e.g. I look at the subject field) to determine if that certificate is allowed past the "second gate". – mikey Jan 22 '14 at 14:45
  • This link is a bit more WCF-specific http://stackoverflow.com/questions/7528455/how-to-get-the-x509certificate-from-a-client-request – mikey Jan 22 '14 at 14:49