13

I'm trying to access a publicly-hosted SOAP web service (not WCF) over https, and I'm getting an error that I've never seen before. First, here are the facts:

  • This service requires client certificates. I have a certificate that is signed by the same CA as the server's certificate.
  • I know that the URL is available, as I can hit it in Internet Explorer. IE brings up the "choose certificate" window, and if I pick it (and ignore the server-host-name-does-not-match-certificate error), it goes on and gives me an HTTP 500 error.
  • If I open the site in Chrome, after picking the cert and ignoring the error, I get a normal error message about WSA Action = null.
  • If I open the site in FireFox, after ignoring the error, I get a page about how the server couldn't validate my certificate. It never asked me to pick one, so that makes perfect sense.

Now, the exception:

Error occurred while executing test 12302: System.ServiceModel.Security.SecurityNegotiationException: Could not establish secure channel for SSL/TLS with authority 'ihexds.nist.gov:9085'. ---> System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)

I've traced the interaction with WireShark, but because I'm not an expert in the TLS protocol, I could be missing clues as to what's going on. Here, however, is what I do see:

  1. C -> S Client Hello
    • Contains things like a random number, date/time, cypher suites supported, etc
  2. S -> C Server Hello, Certificate, Certificate Request, Server Hello Done
    • Contains the server's certificate, and a request for a client certificate
  3. C -> S Certificate, Client Key Exchange, Change Cipher Spec, Encrypted Handshake Message
    • HERE IS THE INTERESTING PART -- The first part of this packet is the Certificate handshake, where I assume the client certificate would be, but there are no certificates present (Certificates Length: 0).
  4. S -> C Alert (Level: Fatal, Description: Bad Certificate)
    • Well, yeah, there was no certificate sent.

My binding is set up as follows:

<binding name="https_binding">
    <textMessageEncoding />
    <httpsTransport useDefaultWebProxy="false" />
</binding>

My behavior is set up as follows:

<behavior name="clientcred">
    <clientCredentials>
        <clientCertificate findValue="69b6fbbc615a20dc272a79caa201fe3f505664c3" storeLocation="CurrentUser" storeName="My" x509FindType="FindByThumbprint" />
        <serviceCertificate>
            <authentication certificateValidationMode="None" revocationMode="NoCheck" />
        </serviceCertificate>
    </clientCredentials>
    <messageInspector />
</behavior>

My endpoint is set up to use both the binding and the behavior. Why does WCF refuse to send the certificate when it creates the https connection?

Mark
  • 11,257
  • 11
  • 61
  • 97

3 Answers3

10

I solved the problem, but I do not understand why this configuration change fixed it. I changed this line:

<httpsTransport useDefaultWebProxy="false" />

to this:

<httpsTransport useDefaultWebProxy="false" requireClientCertificate="true" />

and magically it started working. I had understood that the requireClientCertificate "knob" was for server-side, so I hadn't tried it during my wrangling. Apparently I was wrong.

Mark
  • 11,257
  • 11
  • 61
  • 97
  • 2
    I hate WCF so so much. This solution worked for me, thanks heaps - but it's all so fiddly. Kill me now. – robnick Aug 09 '17 at 03:04
2

There should have been a CertificateRequest from the server, naming acceptable cert types and CAs. If your certificate doesn't match those it won't be sent.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • There was a certificate request (see #2), and it did indeed contain a list of CAs and certificate types. I do indeed have an appropriate certificate, and it is the one specified in the behavior. – Mark Nov 04 '10 at 14:49
  • If all that is true there would have been a Certificate message from the client after the CertificateRequest from the server. The inescapable conclusion is that some of it isn't true. You need to double check it all: specifically, that the certificate (a) is available to the application and (b) conforms with all the constraints expressed in the CertificateRequest. – user207421 Nov 05 '10 at 02:46
  • It's verifiably true... I have the WireShark capture right here. I did end up solving the problem, though, but I don't really understand why what I changed fixed it. I'll post it in a separate answer. – Mark Nov 08 '10 at 19:10
  • It's verifiably true that you got the CertificateRequest message and that you didn't send a Certificate. That's what your dump above shows. If there had been a client Certificate message it would have appeared in response to the request. – user207421 Aug 08 '15 at 00:23
  • Yes, that's what I said. The whole question boils down to, "the server requested a client certificate, why didn't WCF send one?" – Mark Aug 12 '15 at 12:26
  • @Mark And the answer is given in what *I* said in the last sentence of my answer, and again in my first comment. – user207421 Apr 28 '17 at 07:49
  • the answer is the one I wrote and accepted six and a half years ago. – Mark May 02 '17 at 01:10
0

It could be a problem negotiating which security protocol to use. Specifically im thinking that the server might not like WCF trying to use TLS 1.0.

To see if this is the case try to add the following before invoking the service

System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Ssl3

This could be added either in client code or by placing it in an IEndpointBehavior

magnus
  • 813
  • 2
  • 8
  • 15
  • I tried this, and it didn't change the results. I do know the server supports TLS 1.0 (and only one specific cipher, in fact, but that cipher is in the list sent to the server in the handshake). – Mark Nov 04 '10 at 14:51
  • Not if the exchange got as far as a ChangeCipherSpec message. That means that everything about the protocol has been agreed. – user207421 Aug 08 '15 at 00:21