Bug 52675 - HttpListener doesn't work with SSL
Summary: HttpListener doesn't work with SSL
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: Mono.Security (show other bugs)
Version: 4.8.0 (C9)
Hardware: PC Linux
: --- normal
Target Milestone: Untriaged
Assignee: Martin Baulig
URL:
Depends on:
Blocks:
 
Reported: 2017-02-22 18:16 UTC by markolog
Modified: 2017-10-11 17:43 UTC (History)
5 users (show)

Tags: TLS, SSL, HttpListener
Is this bug a regression?: No
Last known good build:


Attachments
TestCase (899 bytes, application/force-download)
2017-03-23 12:36 UTC, weber
Details
patch (640 bytes, patch)
2017-03-31 19:31 UTC, Martin Frydl
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description markolog 2017-02-22 18:16:36 UTC
I'm unable to run HttpListener with SSL on Ubuntu 16.04, mono 4.8:
-------------------------------------------------------------------------------
Mono JIT compiler version 4.8.0 (Stable 4.8.0.489/9ac5bf2 Wed Feb 15 10:25:57 UTC 2017)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug
        LLVM:          supported, not enabled.
        GC:            sgen


This is the sample code I'm trying to run:
------------------------------------------------------------------------------
static void Main(string[] args)
        {
            try
            {
                var listener = new HttpListener();
                string prefix = "https://+:443/";
                listener.Prefixes.Add(prefix);

                Console.WriteLine("Starting HTTP server at " + prefix);

                listener.Start();

                while (true)
                {
                    try
                    {
                        Console.WriteLine("listening for request...");
                        var context = listener.GetContext();
                        Console.WriteLine(context.Request.Url);
                    }
                    catch (Exception e)
                    {
                        Console.ForegroundColor = ConsoleColor.Red;
                        Console.WriteLine("Exception processing request: " + e);
                        Console.ResetColor();
                    }
                }
            }
            catch (Exception e)
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("Exception caught! " + e);
            }
        }

This is the error I receive:
------------------------------------------------------------------------------
useracc@desk:~/projects$ sudo mono --debug testssl.exe
Starting HTTP server at https://+:443/
listening for request...

Unhandled Exception:
System.IO.IOException: Remote prematurely closed connection.
  at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncProtocolRequest asyncRequest, Mono.Net.Security.AsyncOperationStatus status) [0x0001b] in <1ad50d57fda24e15afa9ae11713723af>:0
  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (Mono.Net.Security.AsyncOperationStatus status) [0x0009e] in <1ad50d57fda24e15afa9ae11713723af>:0
  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation () [0x0000d] in <1ad50d57fda24e15afa9ae11713723af>:0
  at Mono.Net.Security.AsyncProtocolRequest.StartOperation () [0x00000] in <1ad50d57fda24e15afa9ae11713723af>:0
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <f712f98eb8e445c8918edaf595bbe465>:0
  at Mono.Net.Security.MobileAuthenticatedStream.ProcessAuthentication (System.Net.LazyAsyncResult lazyResult) [0x00083] in <1ad50d57fda24e15afa9ae11713723af>:0
  at Mono.Net.Security.MobileAuthenticatedStream.AuthenticateAsServer (System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, System.Boolean clientCertificateRequired, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) [0x00010] in <1ad50d57fda24e15afa9ae11713723af>:0
  at Mono.Net.Security.Private.MonoSslStreamWrapper.AuthenticateAsServer (System.Security.Cryptography.X509Certificates.X509Certificate serverCertificate, System.Boolean clientCertificateRequired, System.Security.Authentication.SslProtocols enabledSslProtocols, System.Boolean checkCertificateRevocation) [0x00006] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Net.HttpConnection.Init () [0x0001d] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Net.HttpConnection..ctor (System.Net.Sockets.Socket sock, System.Net.EndPointListener epl, System.Boolean secure, System.Security.Cryptography.X509Certificates.X509Certificate cert) [0x00096] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Net.EndPointListener.ProcessAccept (System.Net.Sockets.SocketAsyncEventArgs args) [0x00052] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Net.EndPointListener.OnAccept (System.Object sender, System.Net.Sockets.SocketAsyncEventArgs e) [0x00000] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Net.Sockets.SocketAsyncEventArgs.OnCompleted (System.Net.Sockets.SocketAsyncEventArgs e) [0x00014] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Net.Sockets.SocketAsyncEventArgs.Complete () [0x00000] in <1ad50d57fda24e15afa9ae11713723af>:0
 at System.Net.Sockets.Socket.<AcceptAsyncCallback>m__0 (System.IAsyncResult ares) [0x000a0] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Net.Sockets.SocketAsyncResult+<Complete>c__AnonStorey0.<>m__0 (System.Object _) [0x00000] in <1ad50d57fda24e15afa9ae11713723af>:0
  at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem () [0x00019] in <f712f98eb8e445c8918edaf595bbe465>:0
  at System.Threading.ThreadPoolWorkQueue.Dispatch () [0x00096] in <f712f98eb8e445c8918edaf595bbe465>:0
  at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback () [0x00000] in <f712f98eb8e445c8918edaf595bbe465>:0

The certificates seams OK, added to certmgr and to httpcfg.
I tried also to define the new tls provider:
export MONO_TLS_PROVIDER="btls"

and to define tls1.2 inside C# code:
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Comment 1 markolog 2017-02-22 18:20:12 UTC
The error is thrown when I do HTTP request either GET or POST.
Comment 2 markolog 2017-02-23 19:38:36 UTC
Running with stack trace:
---------------------------------------------------------------------
sudo mono --debug=mdb-optimizations --trace=N:system.Net testssl.exe
Starting HTTP server at https://172.16.1.59:443/
[0x7faddf83c740:] EXCEPTION handling: Mono.Btls.MonoBtlsException: MonoBtlsPkcs12.Import failed.
[0x7faddf83c740:] EXCEPTION handling: Mono.Btls.MonoBtlsException: MonoBtlsPkcs12.Import failed.
listening for request...
[0x7fadd72bf700:] EXCEPTION handling: System.IO.IOException: Remote prematurely closed connection.
[0x7fadd72bf700:] EXCEPTION handling: System.IO.IOException: Remote prematurely closed connection.
[0x7fadd72bf700:] EXCEPTION handling: System.IO.IOException: Remote prematurely closed connection.

The certificates supposed to be OK because they are also used by NGINX without problems and they pass openssl validations:
openssl x509 -in ServerCert.cer -inform der -text -noout
openssl x509 -in ServerCert.pem -text -noout
openssl pkcs12 -info -in ServerCert.pfx
Comment 3 markolog 2017-03-11 14:30:38 UTC
I updated mono version to 4.8:

Mono JIT compiler version 4.8.0 (Stable 4.8.0.495/e4a3cf3 Wed Feb 22 18:30:58 UTC 2017)
Copyright (C) 2002-2014 Novell, Inc, Xamarin Inc and Contributors. www.mono-project.com
        TLS:           __thread
        SIGSEGV:       altstack
        Notifications: epoll
        Architecture:  amd64
        Disabled:      none
        Misc:          softdebug
        LLVM:          supported, not enabled.
        GC:            sgen

The mono passes this test that didn't pass in past:
MONO_TLS_PROVIDER=btls csharp -e 'Console.WriteLine (new System.Net.WebClient ().DownloadString ("https://www.howsmyssl.com/").IndexOf ("1.2"))'

And I'm receiving now different error:

sudo mono --debug=mdb-optimizations --trace=N:system.Net testssl.exe
Starting HTTP server at https://*:40510/
[0x7f7ae207b740:] EXCEPTION handling: Mono.Btls.MonoBtlsException: MonoBtlsPkcs12.Import failed.
[0x7f7ae207b740:] EXCEPTION handling: Mono.Btls.MonoBtlsException: MonoBtlsPkcs12.Import failed.
listening for request...
[0x7f7addb75700:] EXCEPTION handling: System.IO.IOException: Remote prematurely closed connection.
[0x7f7addb75700:] EXCEPTION handling: System.IO.IOException: Remote prematurely closed connection.

Unhandled Exception:
System.IO.IOException: Remote prematurely closed connection.
  at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncProtocolRequest asyncRequest, Mono.Net.Security.AsyncOperationStatus status) [0x0001b] in <5641e4edad4f4464ba58c620a7b8ea48>:0
  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation (Mono.Net.Security.AsyncOperationStatus status) [0x0009e] in <5641e4edad4f4464ba58c620a7b8ea48>:0
  at Mono.Net.Security.AsyncProtocolRequest.ProcessOperation () [0x0000d] in <5641e4edad4f4464ba58c620a7b8ea48>:0
  at Mono.Net.Security.AsyncProtocolRequest.StartOperation () [0x00000] in <5641e4edad4f4464ba58c620a7b8ea48>:0
--- End of stack trace from previous location where exception was thrown ---

The certificates pass this test:
openssl s_server -key server.dec.pem -cert server.pem -CAfile cacert.pem -accept 40510 -www
openssl s_client -CAfile cacert.pem -connect 172.16.xx.xx:40510
Comment 4 weber 2017-03-23 12:36:02 UTC
Created attachment 20747 [details]
TestCase

I think the problem is that the OnAccept path of the System/System.Net/EndPointListener doesn't handle exceptions at all.

That way any Exception, that will occure while the handshake is in progress (even if the client is terminating the connection early), will result in a uncatched exception that terminates the entire runtime.

Attached you will find a minimized test case for that scenario.

When i run curl with the --insecure flag everything is fine.
But when i run it without that flag, curl detects that the connection is insecure (that's not the real problem here) and closes it, which results in a runtime termination.
Comment 5 Martin Frydl 2017-03-31 19:31:03 UTC
Created attachment 21118 [details]
patch

I've created a patch catching the exception in HttpConnection constructor and closing the socket when such occurs. This seems consistent with .NET behavior which just closes socket on any error.

I've also hit the same error when accidentally connecting to HTTPS port using HTTP protocol, just with different exception message.
Comment 6 weber 2017-04-01 11:28:37 UTC
Yes this patch fixes the issue!
Comment 7 Alexander Köplinger [MSFT] 2017-10-11 17:43:42 UTC
The pull request with this patch was merged: https://github.com/mono/mono/pull/5724. Thank you!