Search code examples
wcfwcf-securityx509certificate

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


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


Solution

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