Wednesday, April 15, 2009

WCF Gotcha: Disabling SSL Validation

@YaronNaveh

When you use SSL with WCF or .Net 2.0 web services you might get this exception:


SecurityNegotiationException:

Could not establish trust relationship for the SSL/TLS secure channel with authority 'localhost'.


This means that the X.509 certificate that the server presented is not valid according to your client's trust chain. the trust chain is the list of certificate issuers that you trust. In many cases this means you should not trust this web service. In some cases you decide to trust it anyway, due to the fact that you know the author or are still in early testing stages. You have two options:

Option 1 - Make the certificate valid
You would need to have the server certificate or its issuer's certificate in the trusted certificates store of your client. This can be done using WinHttpCertCfg.exe or using the "mmc" console.

Option 2 - Configure WCF/.Net 2.0 to not validate the certificate
With WCF, a common gotcha is to try and achieve that by setting:


<serviceCertificate>
<authentication certificateValidationMode="None" />
</serviceCertificate>


However this will not work with transport level security (SSL) but only with message level security. The correct way to do it is the same one as with .Net 2.0 web services. Just add this code before calling the service:


using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
...
ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(OnValidationCallback);
...
public static bool OnValidationCallback(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors errors)
{
return true;
}

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

17 comments:

Ookami said...

חבר, אני לא מבין פה כלום
אבל הבלוג שלך נראה מצויין ובתמורה קיבלת כמה הקלקות
:)

www.eazybay.blogspot.com

Jagdish said...

Hello Yaron,

Your blog is pretty neat and very much needed for all the folks who are tyring to adventure into WCF especially from Java based client invoked Microsoft implementations.

We have disabled as you mentioned
authentication certificateValidationMode="None"

However we get the exception below:
javax.xml.ws.soap.SOAPFaultException: The security context token is expired or is not valid. The message was not processed.

However, we have not added the code that you mentioned along with that config change? Do you think adding the code would solve this issue?

Thanks much
- Jagdish

Yaron Naveh (MVP) said...

Hi Jagdish

It seems like there is a mismatch between client and server settings.

First I would try to add WCF tracing to the server to see what exactly it complains upon.

Then I would build a WCF client that works with this WCF server and compare the outgoing SOAP of the WCF and Java clients.

Note that not every WCF setting is interoperable so you need to carefully configure the WCF side.

Yaron

Jagdish said...

Hello Yaron,

Thank you for your reply.

We are going to enableECF tracing and send across the trace.

Thanks
- Jagdish

Vinoth K G said...
This comment has been removed by the author.
Yaron Naveh (MVP) said...

Vinoth

You have published the java side stack trace, but it does not contain all the information. See here how to configure tracing & logging on the WCF side:

http://blogs.msdn.com/madhuponduru/archive/2006/05/18/601458.aspx

The WCF trace can give us a more detailed exception. Also we would need to look in the actual request that is sent.

Not all WCF settings are interoperable (for example the default ones aren't) so depending on your needs you should configure the WCF side correctly.

Vinoth K G said...
This comment has been removed by the author.
Yaron Naveh (MVP) said...

Vinoth - I answered to your mail privately

Anonymous said...

Hi Yaron,

I'm really new to WCF (like 4 days new LOL). So I'm using WSHttp with message level security and the built in UserNamePassword. Now I created a self-signed pfx and put it in LocalMachine\Root (trusted CAs).

I never liked any code generated tool so I won't use the proxy that gets created by svcutil. So the client communication layer code is entirely mine but I do use svcutil for getting the base64 public key and hardcoding it into the client code since I'm not able to understand how can I extract that myself.

So my question is more like PKI X509 certs related than WCF. Can you please explain the process of extracting that from a pfx? Also how would this enable sideways authentication for both parties using just the server cert? Isn't a cert needed on the client side in order for the server to authenticate to the client?

I really enjoy reading your blog. Thanks alot.

Jon

Yaron Naveh (MVP) said...

Jon

Client authentication is optional. If you choose to use it then you either need a client certificate (as you mentioned) or a client user/pass or something else. It depends if you need it.

As for extracting the "public certificate", one way is this:

1. Start-->run-->mmc
2. File-->add remove snap-in
3. Add...
4. Choose certificates
5. Choose My User Account or Computer Account
6. Approve all

Now you can see your certificates and right-click-->export... the one you wish.

Unknown said...

Hi Yaron,

I am facing problem when adding service reference in my VS2010. When I hit the service address with ?wsdl in browser, it asks me for a certificate and I see the wsdl on IE.But when I do the same in VS2010 it finds the service though but doesnt ask me for certificate and doesnt add code in my app.config for the endpoint. So when I did some research, suggestions were to copy the wsdl into a file and then use svcutil.exe . Tried that as well but gor the port type error when creating proxy. Could you please let me know where the problem could be?

Thanks a Ton

Yaron Naveh (MVP) said...

Hi Kedar

You should ask the service author for a sample working soap message. this can help deciding which binding to use.

erdinc said...

Hello Yaron,

I got same error. I have a WCF application and a Windows Service created developed with c#. When I run the windows service with account logon I certificate authentication works well. But I need to run the windows service with "Local System account". When I change to "Local System account" I got SecurityNegotiationException - Could not establish secure channel for SSL/TLS with authority 'xxx.xxx.xxx.xxx'.

I added all certificates to Computer account stores(Personal & Trusted Root Certification Authorities) with mmc window. But I cannot handle and solve this.

Also I tried this code to bypass certificate validation but it didn't work.


System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate,
System.Security.Cryptography.X509Certificates.X509Chain chain,
System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true;
};


Do you have any ideas about this?

Thanks

Yaron Naveh (MVP) said...

is there an inner exception?
when you put a breakpoint on y oru latest code chunk does it get called?

erdinc said...

Hi Yaron,

Thanks for reply.

Here is my inner exception;

Message: The request was aborted: Could not create SSL/TLS secure channel.

StackTrace:
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)


When i try to get data from my WCF service I got this exception.

Yaron Naveh (MVP) said...

seems like it's not related to WCF - try to repro it by sending GET or POST to the server using Webclient or HttpWebRequest. Also verify if the ServerCertificateValidationCallback is called at all by putting a breakpoint on it.

erdinc said...

I tried to put breakpoint on ServerCertificateValidationCallback, it's calling but still having this exception.