2

I have a self-hosted WCF REST service based on the WebHttpBinding. One of the methods on the service looks something like this:

    [OperationContract]
    [WebInvoke(Method = "POST", UriTemplate = "myMethod")]
    Stream MyMethod(Stream contents);

I wrote a simple test program that creates a HttpWebRequest to try and POST data to this method. This works fine in the following scenarios:

  1. Service is not using any security.
  2. Service is using transport security without client certificate.
  3. Service is using transport security with client certificate and I POST 0 bytes.

If I try to use transport security with a client certificate a POST more than 0 bytes, the service returns HTTP 403 (forbidden), and it never hits any of my code.

This is driving me nuts.

Any ideas?

UPDATE

After enabling tracing for http.sys, I observed the following message in the trace:

Attempt by server application to receive client certificate failed with status: 0xC0000225.

Does anyone know what this means? I'm certain that I'm sending the client certificate and certain that it's trusted by the host machine.

Peter Ruderman
  • 12,241
  • 1
  • 36
  • 58
  • We are using wcf streaming with transport level security and client certifiactes. but our service is selfhosted. Are you hosting wcf under IIS? which version? Did you mapped client certificate with Windows users? – Sergey Mirvoda Dec 15 '10 at 19:49
  • Well, that's hopeful. We are self-hosting the service. The client certificates are not mapped to user accounts. We're using a custom role provider. – Peter Ruderman Dec 15 '10 at 22:29

3 Answers3

0

You probably need to set a SSL certificate for your local host.

1) Run --> "mmc"

2) File --> Add/Remove Snap-In...

3) Under "Available snap-ins" select "Certificates" and "Add > "

4) Select "Computer account"

5) Click "Next"

6) Click "Finish"

7) Click "Ok"

8) Look in Personal --> Certificates I think you should have a 127.0.0.1

9) Click and drag that certificate to "Trusted Root Certificate Authorities"

Then whatever address you use, you need to change that URL to 127.0.0.1 (not localhost) as that won't work. The certificate should then be valid and I think you will be able to get past authorization.

If you are having other problems then it's probably not your certificate, so ensure your services, behaviors and bindings are accurate.

A way to help you use WCF tracing to see what exactly the problem might after that, I will shamelessly point you to my blog post. :)

http://jtstroup.net/post/Wcf-Tracing.aspx

Good luck.

jtstroup
  • 73
  • 6
  • Thanks for your reply, but I'm fairly certain it isn't a certificate problem. Both the service and client certificates are trusted on my machine and the service certificate subject matches the URL I'm using to make the request. Everything works when I use just a service certificate but breaks when I use a client certificate and try to post a non-zero amount of data. – Peter Ruderman Dec 14 '10 at 19:23
0

You need to enable security in both client and server

  1. On server, in web config you should set up security binding : TRANSPORT and CERTIFICATE

  2. On Client when you are creating your HttpWebRequest you also have to enable TRANSPORT and CERTIFICATE . You also should programmaticly assign a client certificate .

  3. SSL Port ( 443 ) should be opened - check by telnet.

  4. Sometimes POST verb is disabled by IIS . You have to enable it

if you need more details or have a question post some code and web.config file.

Old Programmer
  • 546
  • 1
  • 4
  • 17
  • Thanks for your reply, but I don't think any of this applies. The server is using transport security with client certificates. I'm using a HttpWebRequest to send the request, which is not a WCF class. I do attach the client certificate. Port 443 is certainly open since everything works fine when I don't require a client certificate. I don't see how IIS could interfere since this is a self-hosted WCF application. – Peter Ruderman Dec 22 '10 at 20:19
0

After long and painful searching, I finally discovered that the problem was a corrupt client certificate. Although there were no outward indications, the private key for this certificate was not saved on the local machine. We generated the certificate in code, and then imported it into the current user's personal store. We did not, however, set the RSACryptoServiceProvider.PersistKeyInCsp property on the object used to generate the private key. As a result, .NET deleted the private key container and the imported certificate ended up referencing a non-existant private key.

The response to this post goes over the gotchas in importing certificates with .NET in some detail: Inserting certificate with private key.

Community
  • 1
  • 1
Peter Ruderman
  • 12,241
  • 1
  • 36
  • 58