Tuesday, January 31, 2017

Web Api call fails now after TLS 1.2 is enforced between our servers

Leave a Comment

We have a server with a windows service that calls an web api over https in other server (both servers internals) and it was working normal, until they were changed their TLS configuration.

I coded a simple console app for test the call and reproduced the error. I tested from Firefox from the machine acting as client and is respoding ok (this discard any firewall or port blocks issue) More strange is I tested from my laptop (win7) and worked ok.

As can be seen in the Exception details fails "at System.Net.TlsStream.EndWrite(...)" so seems to be related with changed configuration. After a lot of research I found some changes done in Registry (not done by me, because I can't but for support area), and change my code adding ServicePointManager.SecurityProtocol for support Tls.

Any Ideas?

Following almost all instructions on: https://blogs.msdn.microsoft.com/dataaccesstechnologies/2016/07/12/enable-tls-1-2-protocol-for-reporting-services-with-custom-net-application/

  • Development: Visual Studio: 2013
  • .Net Framework: version 4.5
  • Operation System: Windows Server 2008 R2 Service Pack 1

Registry found (made by support personal, these are some of them)

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\SSL 3.0\Client] "Enabled"=dword:00000000 "DisabledByDefault"=dword:00000001  [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Client] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001  [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\Server] "Enabled"=dword:00000001 "DisabledByDefault"=dword:00000000 

Sample Console app for testing:

public async Task<string> TestApiCall() {     const string uri = "https://myserver/api/blahblah";     try     {         using (var client = new HttpClient())         {             //client.DefaultRequestHeaders.Accept.Clear();             //client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("*/*"));             client.DefaultRequestHeaders.Add("Connection", "close"); // Keep Alive = false (tested with & without this line)              ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; // tested with almost all combinations since only Tls12             ServicePointManager.SecurityProtocol &= ~SecurityProtocolType.Ssl3; // Disable SSL3              //ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };             ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;  // Accept possible invalid certificates (not recomended, only for test), tested without this line too              var response = await client.GetAsync(uri).ConfigureAwait(false);  // <-- Exception thrown here             response.EnsureSuccessStatusCode();             var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);             return result;         }     }     catch (Exception ex)     {         Console.WriteLine(ex.ToString());     } } 

Exception thrown:

System.Net.Http.HttpRequestException: An error occurred while sending the request.      ---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.      ---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.      ---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host        at System.Net.Sockets.Socket.BeginReceive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags, AsyncCallback callback, Object state)        at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32 offset, Int32 size, AsyncCallback callback, Object state)        --- End of inner exception stack trace ---        at System.Net.TlsStream.EndWrite(IAsyncResult asyncResult)        at System.Net.PooledStream.EndWrite(IAsyncResult asyncResult)        at System.Net.ConnectStream.WriteHeadersCallback(IAsyncResult ar)        --- End of inner exception stack trace ---        at System.Net.HttpWebRequest.EndGetResponse(IAsyncResult asyncResult)        at System.Net.Http.HttpClientHandler.GetResponseCallback(IAsyncResult ar)        --- End of inner exception stack trace ---        at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)        at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)        at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()        at TestHttp.Program.<TestApiCall>d__2.MoveNext() 

1 Answers

Answers 1

You can try adding a certificate file send to server. Usually this certificate file is open by the certificate CA ROOT.

    ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate;     HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);     X509Certificate cer = new X509Certificate("F:\\csharp2.cer");  //adding your client certificate.         httpWebRequest.ClientCertificates.Add(cer);         httpWebRequest.BeginGetResponse(CallBack(), httpWebRequest);         private void CallBack()     {         AsyncCallback ac = (result) =>         {              HttpWebRequest webRequest = (HttpWebRequest)result.AsyncState;              using (HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(result))             {                 //response             }         };     }       private static bool ValidateServerCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)     {         return (sslPolicyErrors == SslPolicyErrors.None);     } 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment