Friday, March 9, 2012

Solving "Received an unexpected EOF or 0 bytes from the transport stream" issue

One of the popular sayings appears to be correct when saying that most of the things are not so easy as they seem to be. Calling a web service with transport security enabled - this is what I'd expect to be easy. And it does... until something similar shows up: 

System.ServiceModel.CommunicationException: An error occurred while making the HTTP request to https://xxx.xxx.xxx. 
This could be due to the fact that the server certificate is not configured properly with HTTP.SYS in the HTTPS case. 
This could also be caused by a mismatch of the security binding between the client and the server. 
---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. 
---> System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream.
   
My first idea was that the error was caused by the certificate validation issue so I tried to apply the solution mentioned in my earlier post. No luck this time.

After some research the problem was solved by setting:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3

Quick note, why this was helpful.
It's all related to protocols - SSL3 and TLS - used to establish a secure communication between two endpoints.

  • SSL3 is a security protocol released in 1996 by Netscape Communications and it is a superset of SSL2. 
  • TLS (TLS 1.0 or sometimes known as SSL 3.1) was introduced by IETF in 1999 (RFC 2246) and is a superset of SSL3 although not 100% backward compatible.

More information about the protocols mentioned above could be found here.

.NET applications use TLS for transport security by default. If you look at the static constructor of the ServicePointManager class you would notice the following line:

s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;

My wild guess would be that initially TLS protocol is used to establish a secure connection with the server. In case when the server does not support TLS, the negotiation continues using SSL3 protocol. The problem is that some servers not supporting TLS terminate connection immediately. This is why in such cases SSL3 communication needs to be forced.

2 comments:

  1. I was developing a C++ HTTPS server using SSPI/Schannel, and when I tested with C# .NET WebClient as the client I received this error. Forcing the protocol to SSL 3.0 rather than TLS 1.0 as described above worked around the problem, but I did find that there was a bug in my C++ code that was causing the issue with TLS. After calling EncryptMessage(), I was sending the entire buffer I had allocated without checking the actual sizes of the TLS header, data, and trailer that were returned by EncryptMessage(). Particularly, the trailer was 9 bytes shorter than the maximum size that was indicated by SecPkgContext_StreamSizes.cbTrailer, so I was sending 9 extra bytes of bad data. This was apparently what the .NET client didn't like - after fixing this issue, both SSL 3.0 and TLS 1.0 worked.

    ReplyDelete
  2. Thank you! I was having this exact problem and that one simple line solved it. Well done and thank you for sharing.

    ReplyDelete