In this article, I want to show a problem I faced trying to connect a .NET client to a server using SSL/TLS and certificate authentication for both client and server. To forestall my problem, I got a timeout. But let’s look at the some details first. Here is the wire capture of a successful connection:
As you can see, client and server perform a correct SSLv3 handshake. Near the ending of the handshake at frame 11, the server asks for a client certificate using a Certificate Request message. The client answers the request by sending a Certificate message (frame 12). Afterwards, the handshake is completed and the encrypted application communication (frame 15 and following).
The .NET framework provides lots of features that enable communication over SSL/TLS, so I thought it would be easy. I decided to try some very basic code using the HttpWebResponse class. This is the code I wrote:
// for this demo, we'll just accept the server certificate ServicePointManager.ServerCertificateValidationCallback = delegate { return true; }; // get the client certificate from the certificate store var store = new X509Store(StoreName.My, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadOnly); var cert = store.Certificates.Find(X509FindType.FindBySubjectName, certificteSubject, false)[0]; // create the web request... var request = (HttpWebRequest)WebRequest.Create(url); request.ClientCertificates.Add(cert); request.UserAgent = "SSL Demo"; request.Method = "GET"; // ... and connect var response = request.GetResponse(); using(var r = new StreamReader(response.GetResponseStream())) { Console.Write(r.ReadToEnd()); }
To my surprise, it did not work. Instead, I got a timeout exception at line 17. What happened? To answer that, lets take a look at the wire capture for this connection attempt:
What you see in the image is the complete communication between client and server (there are no further messages beyond frame 12). As you can see, up to frame 11 the messages in this case are quite the same as in the latter example when everything worked fine (frame 5 contains the Server Hello Message, but that line is truncated in the screen shot). The main difference, though, is that the client is using TLSv1 instead of SSLv3. Now, this should’nt be a problem since the two protocols are nearly identical. The differences here are that a technique called Server Name Indication is used (this is what causes the Alert in frame 5, but this does not cause any harm, I think) and that a different cipher suite is used. Except for that, the messages very equal.
The one thing that is very different in the latter case is that after receiving a Certificate Request message, the client sends a TCP ACK message, but no certificate. In this case, the server is still waiting for the certificate so it does not answer. But what is the client waiting for? To be honest, I don’t know. If anyone find’s out what the reason for this is, please tell us.
Nevertheless, I needed a solution. So after finding this entry at StackOVerflow, I managed to get it working. The solution was to explicitly tell .NET to use SSLv3 instead of TLSv1. The following line of code should appear before initiating the communication:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3;
Again, I don’t know why this happens. In theory it should have worked with TLSv1 in the first place. But since SSLv3 and TLSv1 are so identical (see this paper for the differences), it should not make any difference.