I have a .NET application that invokes a SOAP web service and it has been working for years but it stopped working few days ago after a Windows (Server 2012 R2) security update (there are many and I don't know which one). Microsoft has published some articles about the issue but all the described workarounds didn't work :
https://support.microsoft.com/en-us/help/3155464/ms16-065-description-of-the-tls-ssl-protocol-information-disclosure-vu
https://support.microsoft.com/en-us/help/3069494/cannot-connect-to-a-server-by-using-the-servicepointmanager-or-sslstre
The service that I'm invoking is using SSL3/TLS1.0 and the provider can't/wouldn't upgrade it to TLS1.2. Also I tested my application in old Windows 2008R2 that have no .NET4 updates and it worked as it did before.
My Code :
string url = "https://weblogic_server:7070/app/Service";
string text = "<soapenv:Envelope>...</soapenv:Envelope>";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, error) =>
{
return true;
};
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;
//ServicePointManager.Expect100Continue = false; // did nothing good
//ServicePointManager.UseNagleAlgorithm = false; // did nothing good
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(text);
request.ContentType = "text/xml; encoding='utf-8'";
request.Timeout = 1000000000;
request.ContentLength = bytes.Length;
request.KeepAlive = true;
request.Method = "POST";
using (Stream stm = request.GetRequestStream()) // Exception
{
using (StreamWriter stmw = new StreamWriter(stm))
{
stmw.Write(text);
}
}
using (StreamReader responseReader = new StreamReader(request.GetResponse().GetResponseStream()))
{
string resultText = responseReader.ReadToEnd();
HttpWebResponse resp = (HttpWebResponse)request.GetResponse();
Console.WriteLine(resp);
Console.WriteLine(resultText);
}
The Exception code is :
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send. ---> System.IO.IOException: The handshake failed due to an unexpected packet format.
at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)
at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)
at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.ConnectStream.WriteHeaders(Boolean async)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context)
at System.Net.HttpWebRequest.GetRequestStream()
My question are :
- Is there any other way/workaround to get this invocation work, other than what's described in the articles ?
- The code works fine under .NET2.0 where .NET4.0 is not updated to the .NET4.6, is there a way to force the application to use a specific old System.dll (copied from Windows 2008R2 machine) ? I tried to add it as reference manually but the CLR always uses the GAC's one.
- Is it possible to overload HttpWebRequest
and somehow force it to use SSL3 ?
Thanks.
See Question&Answers more detail:
os 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…