[ssl] "The underlying connection was closed: An unexpected error occurred on a send." With SSL Certificate

Issue : I get this exception "THE UNDERLYING CONNECTION WAS CLOSED: AN UNEXPECTED ERROR OCCURRED ON A SEND" in my logs and it is breaking our OEM integration with our email marketing system at random times varying from [1hour - 4 hours]

My website is hosted on a windows server 2008 R2 with IIS 7.5.7600. This website has a large number of OEM components and comprehensive dashboard. Everything works fine with all the other elements of the website except with one of our email marketing component which we are using as an iframe solution within our dashboard. The way it works is, I send a httpWebRequestobject with all the credentials and i get a url back which i put in an iframe and it works. But it only works for some time [1 hour - 4 hours ]and then i get the below exception "THE UNDERLYING CONNECTION WAS CLOSED: AN UNEXPECTED ERROR OCCURRED ON A SEND" and even if the system tries to get the URL from the httpWebRequest it fails with the same exception. The only way to make it work again is to recycle the application pool or anything is edited in web.config. I am really exhausted all the option that i could think of.

Option tried

Explicitly added, keep-alive = false

keep-alive = true

Increased the time out : <httpRuntime maxRequestLength="2097151" executionTimeout="9999999" enable="true" requestValidationMode="2.0" />

I have uploaded this page to a non SSL website to check if the SSL certificate on our production server is making the connection to drop some how.

Any direction toward resolution is greatly appreciated.

Code :

Public Function CreateHttpRequestJson(ByVal url) As String
    Try
        Dim result As String = String.Empty
        Dim httpWebRequest = DirectCast(WebRequest.Create("https://api.xxxxxxxxxxx.com/api/v3/externalsession.json"), HttpWebRequest)
        httpWebRequest.ContentType = "text/json"
        httpWebRequest.Method = "PUT"
        httpWebRequest.ContentType = "application/x-www-form-urlencoded"
        httpWebRequest.KeepAlive = False
        'ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3

        'TODO change the integratorID to the serviceproviders account Id, useremail 
        Using streamWriter = New StreamWriter(httpWebRequest.GetRequestStream())
            Dim json As String = New JavaScriptSerializer().Serialize(New With { _
            Key .Email = useremail, _
            Key .Chrome = "None", _
            Key .Url = url, _
            Key .IntegratorID = userIntegratorID, _
            Key .ClientID = clientIdGlobal _
            })

            'TODO move it to the web.config, Following API Key is holonis accounts API Key
            SetBasicAuthHeader(httpWebRequest, holonisApiKey, "")
            streamWriter.Write(json)
            streamWriter.Flush()
            streamWriter.Close()

            Dim httpResponse = DirectCast(httpWebRequest.GetResponse(), HttpWebResponse)
            Using streamReader = New StreamReader(httpResponse.GetResponseStream())
                result = streamReader.ReadToEnd()
                result = result.Split(New [Char]() {":"})(2)
                result = "https:" & result.Substring(0, result.Length - 2)
            End Using
        End Using
        Me.midFrame.Attributes("src") = result
    Catch ex As Exception
        objLog.WriteLog("Error:" & ex.Message)
        If (ex.Message.ToString().Contains("Invalid Email")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Email Taken")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Invalid Access Level")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Unsafe Password")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Invalid Password")) Then
            'TODO Show message on UI
        ElseIf (ex.Message.ToString().Contains("Empty Person Name")) Then
            'TODO Show message on UI
        End If
    End Try
End Function


Public Sub SetBasicAuthHeader(ByVal request As WebRequest, ByVal userName As [String], ByVal userPassword As [String])
    Dim authInfo As String = Convert.ToString(userName) & ":" & Convert.ToString(userPassword)
    authInfo = Convert.ToBase64String(Encoding.[Default].GetBytes(authInfo))
    request.Headers("Authorization") = "Basic " & authInfo
End Sub`

This question is related to ssl connection

The answer is


We had this issue whereby a website that was accessing our API was getting the “The underlying connection was closed: An unexpected error occurred on a send.” message.

Their code was a mix of .NET 3.x and 2.2, which as I understand it means they are using TLS 1.0.

The answer below can help you diagnose the issue by enabling TLS 1.0, SSL 2 and SSL3, but to be very clear, you do not want to do that long-term as all three of those protocols are regarded as insecure and should no longer be used:

To get our IIS to respond to their API calls we had to add registry settings on the IIS's server to explicitly enable versions of TLS - NOTE: You have to restart the Windows server (not just the IIS service) after making these changes:

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

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

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

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS
1.1\Server] "DisabledByDefault"=dword:00000000 "Enabled"=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] "DisabledByDefault"=dword:00000000 "Enabled"=dword:00000001

If that doesn't do it, you could also experiment with adding the entry for SSL 2.0:

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

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

To be clear, this is not a nice solution, and the right solution is to get the caller to use TLS 1.2, but the above can help diagnose that this is the issue.

You can speed adding those reg entries up with this powershell script:

$ProtocolList       = @("SSL 2.0","SSL 3.0","TLS 1.0", "TLS 1.1", "TLS 1.2")
$ProtocolSubKeyList = @("Client", "Server")
$DisabledByDefault = "DisabledByDefault"
$Enabled = "Enabled"
$registryPath = "HKLM:\\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\"

foreach($Protocol in $ProtocolList)
{
    Write-Host " In 1st For loop"
        foreach($key in $ProtocolSubKeyList)
        {         
            $currentRegPath = $registryPath + $Protocol + "\" + $key
            Write-Host " Current Registry Path $currentRegPath"
            if(!(Test-Path $currentRegPath))
            {
                Write-Host "creating the registry"
                    New-Item -Path $currentRegPath -Force | out-Null             
            }
            Write-Host "Adding protocol"
                New-ItemProperty -Path $currentRegPath -Name $DisabledByDefault -Value "0" -PropertyType DWORD -Force | Out-Null
                New-ItemProperty -Path $currentRegPath -Name $Enabled -Value "1" -PropertyType DWORD -Force | Out-Null    
    }
}
 
Exit 0

That's a modified version of the script from the Microsoft help page for Set up TLS for VMM. This basics.net article was the page that originally gave me the idea to look at these settings.


In my case the site that I'm connecting to has upgraded to TLS 1.2. As a result I had to install .net 4.5.2 on my web server in order to support it.


I've been having the same issue for days now with an integration that also just "used to work before".

Out of sheer depression, I just tried

 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3;

This solved it for me..even though the integration strictly only makes use of SSLv3.

I came to the realization that something if off since Fiddler reported saying that there is an "empty TLS negotiation cipher" or something of the like.

Hopefully it works!


The below code solved my problem :

request.ProtocolVersion = HttpVersion.Version10; // THIS DOES THE TRICK
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

It if helps someone, ours was an issue with missing certificate. Environment is Windows Server 2016 Standard with .Net 4.6.

There is a self hosted WCF service https URI, for which Service.Open() would execute without errors. Another thread would keep accessing https://OurIp:443/OurService?wsdl to ensure that the service was available. Accessing the WSDL used to fail with:

The underlying connection was closed: An unexpected error occurred on a send.

Using ServicePointManager.SecurityProtocol with applicable settings did not work. Playing with server roles and features did not help either. Then stepped in Jaise George, the SE, resolving the issue in a couple of minutes. Jaise installed a self signed certificate in the IIS, poofing the issue. This is what he did to address the issue:

(1) Open IIS manager (inetmgr) (2) Click on the server node in the left panel, and double click "Server certificates". (3) Click on "Create Self-Signed Certificate" on the right panel and type in anything you want for the friendly name. (4) Click on “Default Web site” in the left panel, click "Bindings" on the right panel, click "Add", select "https", select the certificate you just created, and click "OK" (5) Access the https URL, it should be accessible.


The code below resolved the issue

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls Or SecurityProtocolType.Ssl3

Just add:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


Using a HTTP debugging proxy can cause this - such as Fiddler.

I was loading a PFX certificate from a local file (authentication to Apple.com) and it failed because Fiddler wasn't able to pass this certificate on.

Try disabling Fiddler to check and if that is the solution then you need to probably install the certificate on your machine or in some way that Fiddler can use it.


I've found that this is a sign that the server where you're deploying code has an old .NET framework installed that doesn't support TLS 1.1 or TLS 1.2. Steps to fix:

  1. Installing the latest .NET Runtime on your production servers (IIS & SQL)
  2. Installing the latest .NET Developer Pack on your development machines.
  3. Change the "Target framework" settings in your Visual Studio projects to the latest .NET framework.

You can get the latest .NET Developer Pack and Runtime from this URL: http://getdotnet.azurewebsites.net/target-dotnet-platforms.html


For me it was tls12:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

Go to your web.config/App.config to verify which .net runtime you are using

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
  </startup>

Here is the solution:

  1. .NET 4.6 and above. You don’t need to do any additional work to support TLS 1.2, it’s supported by default.

  2. .NET 4.5. TLS 1.2 is supported, but it’s not a default protocol. You need to opt-in to use it. The following code will make TLS 1.2 default, make sure to execute it before making a connection to secured resource:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12

  1. .NET 4.0. TLS 1.2 is not supported, but if you have .NET 4.5 (or above) installed on the system then you still can opt in for TLS 1.2 even if your application framework doesn’t support it. The only problem is that SecurityProtocolType in .NET 4.0 doesn’t have an entry for TLS1.2, so we’d have to use a numerical representation of this enum value:

ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

  1. .NET 3.5 or below. TLS 1.2 is not supported (*) and there is no workaround. Upgrade your application to more recent version of the framework.

You just change your application version like 4.0 to 4.6 and publish those code.

Also add below code lines:

httpRequest.ProtocolVersion = HttpVersion.Version10; 
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

If you are stuck with .Net 4.0 and the target site is using TLS 1.2, you need the following line instead. ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;

source: TLS 1.2 and .NET Support: How to Avoid Connection Errors


Examples related to ssl

Requests (Caused by SSLError("Can't connect to HTTPS URL because the SSL module is not available.") Error in PyCharm requesting website A fatal error occurred while creating a TLS client credential. The internal error state is 10013 curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number How to install OpenSSL in windows 10? ssl.SSLError: tlsv1 alert protocol version Invalid self signed SSL cert - "Subject Alternative Name Missing" "SSL certificate verify failed" using pip to install packages ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749) Powershell Invoke-WebRequest Fails with SSL/TLS Secure Channel "ssl module in Python is not available" when installing package with pip3

Examples related to connection

Apache Server (xampp) doesn't run on Windows 10 (Port 80) "Proxy server connection failed" in google chrome Failed to connect to mysql at 127.0.0.1:3306 with user root access denied for user 'root'@'localhost'(using password:YES) "The underlying connection was closed: An unexpected error occurred on a send." With SSL Certificate Login to Microsoft SQL Server Error: 18456 How do I start Mongo DB from Windows? java.rmi.ConnectException: Connection refused to host: 127.0.1.1; mySQL Error 1040: Too Many Connection org.apache.http.conn.HttpHostConnectException: Connection to http://localhost refused in android What is the functionality of setSoTimeout and how it works?