Here is another problem I had a couple of days ago: the customer had a critical problem with on one of his .NET applications: he has migrated it to the .NET Framework 2.0, but it doesn’t work anymore under Windows 2000. They have isolated the problem and here is the source code to reproduce the problem:
using System; using System.Text; using System.Net; namespace ConsoleApplication { class Program { static void Main(string[] args) { try { string url = "https://myprotectedsite.com"; WebClient client = new WebClient(); byte[] result = client.DownloadData(url); Console.WriteLine("result len=" + result.Length); } catch (Exception ex) { Console.WriteLine("EXCEPTION: " + ex); } Console.Write("Type enter to exit"); Console.ReadLine(); } } }
The code above works properly on Windows XP and Windows 2003, and it displays “result len=582” (or wathever the lenght of the retrieved http stream is). It works also on Windows 2000 if you compile it with Visual Studio 2003 (i.e. .NET Framework 1.1); however if you compile it with Visual Studio 2005, it doesn’t work under Windows 2000. This is the exception we got:
System.Net.WebException: The underlying connection was closed: Could not establish secure channel for SSL/TLS
at System.Net.WebClient.DownloadDataInternal(Uri address, WebRequest request)
at System.Net.WebClient.DownloadData(Uri address)
at System.Net.WebClient.DownloadData(String address)
at ConsoleApplication.Program.Main(String[] args)
I first thought to something related to the SSL certificate and asked the customer to check this, but everything was fine on that regard.
After some more troubleshooting and tests (enabling Systen.Net tracing on my repro machine as expliained in http://blogs.msdn.com/dgorti/archive/2005/09/18/471003.aspx), it turned out that this is due to the SSL3/TLS negotiation: in WinXP and Win2003 when doing the negotiation we try SSL3 first and if that fails TLS, while on Win2000 we try TLS first and then SSL3. According to the RFC the server should allow us to renegotiate if TLS fails, but the server would just return an error that the negotiation was not successful. In the other 2 scenarios we try SSL3 first and it goes successfully.
This is what I get from the Win2003 log, just before successfully establishing the connection:
System.Net Information: 0 : [3976] InitializeSecurityContext(In-Buffer length=6, Out-Buffer length=0, returned code=ContinueNeeded)
This is what I get from the Win2000 log, just before we throw the exception:
System.Net Information: 0 : [3976] InitializeSecurityContext(In-Buffer length=7, Out-Buffer length=0, returned code=MessageAltered)
The solution to this is to specify the SSL3 propocol type before issuing the request, adding the following line of code in the try block:
try { string url = "https://myprotectedsite.com"; WebClient client = new WebClient(); ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3; byte[] result = client.DownloadData(url); Console.WriteLine("result len=" + result.Length); }
It was not a WebClient issue, I reproed it with HttpWebRequest hitting that particular URL; that web server won’t accept TLS (verified it) and will only work with SSL3.
Hope this helps if you get something similar…
Cheers