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)

See Also:
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

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!

Note You need to log in before you can comment on or make changes to this bug.