11

My application has to talk to different hosts over https, and the default setting of ServicePointManager.SecurityProtocol = TLS served me well up to this day. Now I have some hosts which (as System.Net trace log shows) don't answer the initial TLS handshake message but keep the underlying connection open until it times out, throwing a timeout exception. I tried setting HttpWebRequest's timeout to as much as 5mins, with the same result. Presumably these hosts are waiting for an SSL3 handshake since both IE and Firefox are able to connect to these hosts after a 30-40 seconds' delay. There seems to be some fallback mechanism in .NET which degrades TLS to SSL3, but it doesn't kick in for some reason.

FWIW, here's the handshake message my request is sending (a regular TLS 1.0 CLIENT HELLO message):

00000000 : 16 03 01 00 57 01 00 00-53 03 01 4C 12 39 B4 F9 : ....W...S..L.9..
00000010 : A3 2C 3D EE E1 2A 7A 3E-D2 D6 0D 2E A9 A8 6C 03 : .,=..*z>......l.
00000020 : E7 8F A3 43 0A 73 9C CE-D7 EE CF 00 00 18 00 2F : ...C.s........./
00000030 : 00 35 00 05 00 0A C0 09-C0 0A C0 13 C0 14 00 32 : .5.............2
00000040 : 00 38 00 13 00 04 01 00-00 12 00 0A 00 08 00 06 : .8..............
00000050 : 00 17 00 18 00 19 00 0B-00 02 01 00             : ............    

Is there a way to use SSL3 instead of TLS in a particular HttpWebRequest, or force a fallback? It seems that ServicePointManager's setting is global, and I'd really hate to have to degrade the security protocol setting to SSL3 for the whole application.

Anton Tykhyy
  • 19,370
  • 5
  • 54
  • 56
  • Did you actually test your hypothesis by changing the connection setting to SSL3? – Amnon Jun 12 '10 at 11:53
  • Yes, the hypothesis proved correct. The hosts were Netware, and it seems that it is Netware's policy regarding unrecognized/invalid requests not to respond or give any error messages, presumably to reduce attack surface. – Anton Tykhyy Jun 24 '10 at 06:36

2 Answers2

14

Actually, ServicePointManager settings are per-appdomain. This enabled me to work around the problem by creating a separate appdomain set up to use only SSL3, making my data collection object MarshalByRefObject (both WebClient and WebRequest are marshal-by-ref, but better to reduce the number of cross-appdomain calls) and creating it there. Worked perfectly combined with a timeout-based detection scheme.

Anton Tykhyy
  • 19,370
  • 5
  • 54
  • 56
  • Where did you write this piece of code ? `System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls` – Anish V Jun 06 '16 at 11:36
  • @AnishV or to whom it may concern: `ServicePointManager` object comes from `System.Net` namespace, and maintains a static-like state. So, only "using" that namespace & execute `ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11;` *once* before executing concerned operation(s) does the trick. – kmonsoor Aug 16 '16 at 12:54
4

.NET contains provisions to automatically negotiate down to lower versions of the protocol. The value of ServicePointManager.SecurityProtocol determines the behavior. It can take on 3 different values: SecurityProtocol.Ssl3, SecurityProtocol.Tls, or SecurityProtocol.Ssl3 | SecurityProtocol.Tls. Although global, it can be changed as needed.

I cannot identify a solution without having access to a server with the same buggy behavior. About the only suggestion I can make is to attempt to connect with the Ssl3 | Tls setting, and if that doesn't work then retry with the Ssl3 setting. Try lowering the timeout and catching the timeout exception and then retrying.

EDIT

Much of what I wrote in the previous version of this answer was wrong.

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
  • 8
    In a heavily multi-threaded application, changing global settings is not a good idea and `ServicePointManager.SecurityProtocol` needs to stay the same for the duration of the request, so I did it another way. – Anton Tykhyy Jun 24 '10 at 06:40