2

I'm trying to connect to a WCF service from a WinForms client using an IIS-generated self-signed certificate, but no matter what I do I always get "Could not establish trust relationship for the SSL/TLS secure channel with authority ...".

My Web.config looks like this:

 ...

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

...

<endpoint address="transportCertificate" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_TransportCertificate"
        name="TransportCertificateEndpoint" contract="MyService"/>

My client code looks like this:

private void Ping(string endpointAddress)
{
    var binding = new BasicHttpContextBinding();
    binding.Security.Mode = BasicHttpSecurityMode.Transport;
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;

    var service = new CMServiceReference.CMServiceClient(binding,
        new EndpointAddress(string.Format("{0}/{1}", endpointAddress, "transportCertificate")));

    service.ClientCredentials.ClientCertificate.SetCertificate(
                        StoreLocation.CurrentUser, 
                        StoreName.My,
                        X509FindType.FindBySubjectName, 
                        "server.domain.com");

    service.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;

    service.Ping();
}

Setting the certificate, which has been installed on the client machine, seems to work just fine, but I still always get that same error when calling service.Ping(). I've played around with the CertificateValidationMode options, but none of those seem to make any difference.

Is there something obvious I'm missing?


EDITS BELOW AFTER RESOLVING ISSUE

It turns out that the self-signed certificate was in the wrong store on the client the whole time. It needed to be in Local Machine/Trusted Root Certification Authorities. After that it works fine without "Certificate" being specified on the WCF attribute.

After placing the cert in the right location, I simply updated my Web.config to like like so:

...

<binding name="BasicHttpBinding_TransportCertificate">
      <security mode="Transport">
        <transport clientCredentialType="None" />
      </security>
</binding>

...

<endpoint address="transportCertificate" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_TransportCertificate"
        name="TransportCertificateEndpoint" contract="MyService"/>

and my client code to like like this:

private void Ping(string endpointAddress)
{
    var binding = new BasicHttpContextBinding();
    binding.Security.Mode = BasicHttpSecurityMode.Transport;

    var service = new CMServiceReference.CMServiceClient(binding,
        new EndpointAddress(string.Format("{0}/{1}", endpointAddress, "transportCertificate")));

    service.Ping();
}
Andrew
  • 815
  • 8
  • 17

2 Answers2

1
service.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.PeerTrust;

According to MSDN, X509CertificateValidationMode.PeerTrust means The certificate is valid if it is in the trusted people store, but StoreName.My in the function above means to find the certificate from the personal certificates store, I think this is reason of the problem.

If the certificate is in StoreName.My, you can just remove that line.

Matt
  • 6,010
  • 25
  • 36
  • I tried your suggestion, but am still getting the same error. – Andrew Aug 01 '14 at 14:41
  • 1
    how do you get the certificate? – Matt Aug 01 '14 at 14:42
  • On the client? I'm installing it manually, for now, in the certificate store. – Andrew Aug 01 '14 at 14:45
  • 1
    which certificate store? personal? – Matt Aug 01 '14 at 14:46
  • At the moment, yes. Retrieving the certificate via the client is not an issue. If I modify the findValue parameter on the ClientCertificate.SetCertificate() method to something that does not exist, I get a different error ("Cannot find the X.509 certificate using the following search criteria: StoreName 'My', StoreLocation 'CurrentUser', FindType 'FindBySubjectName', FindValue 'server1.domain.com'.") – Andrew Aug 01 '14 at 14:49
1

I think that error is occurring before your client certificate is involved, i.e. the error is that your client app does not trust the server, not that the server does not trust your client certificate.

If the IIS certificate is self-signed, you need to install that certificate as a trusted root certificate on your local machine.

Or if what you are doing is just for testing purposes, you could do what is suggested in this answer: C# Ignore certificate errors?

This will ignore any trust issues the client has with the server.

Community
  • 1
  • 1
user469104
  • 1,206
  • 12
  • 15
  • This is the answer. The certificate was in the wrong store the whole time. It needed to be in Local Machine/Trusted Root Certification Authorities. After that it works fine without "Certificate" being specified on the WCF attribute. – Andrew Aug 01 '14 at 17:00