sta / websocket-sharp

A C# implementation of the WebSocket protocol client and server
http://sta.github.io/websocket-sharp
MIT License
5.68k stars 1.66k forks source link

Exception while hosting secured websocket #79

Open dhermyt opened 9 years ago

dhermyt commented 9 years ago

Hi,

I tried to start websocket server in secured mode on localhost. For generating self signed certificate I used Pluralsight library (http://blog.pluralsight.com/selfcert-create-a-self-signed-certificate-interactively-gui-or-programmatically-in-net). Here is my code:

public void Start()
    {
        var server = new WebSocketServer(51002, true);
        server.Certificate = GenerateSelfSignedCertificate();
        server.AddWebSocketService<StatisticsListener>(@"/Stats");
        server.Start();
    }

    private X509Certificate2 GenerateSelfSignedCertificate()
    {
        using (CryptContext ctx = new CryptContext())
        {
            ctx.Open();

            X509Certificate2 cert = ctx.CreateSelfSignedCertificate(
                new SelfSignedCertProperties
                {
                    IsPrivateKeyExportable = true,
                    KeyBitLength = 4096,
                    Name = new X500DistinguishedName("cn=localhost"),
                    ValidFrom = DateTime.Today.AddDays(-1),
                    ValidTo = DateTime.Today.AddYears(1),
                });

            return cert;
        }
    }

Here is the exception thrown by webserver:

2014-10-01 14:26:48|Fatal|<>cDisplayClass8.b7:636|WebSocketSharp.WebSocketException: An exception has occurred while reading an HTTP request/response. ---> System.ArgumentOutOfRangeException: Określony argument jest spoza zakresu prawidłowych wartości. Nazwa parametru: value w WebSocketSharp.Ext.EqualsWith(Int32 value, Char c, Action1 action) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\Ext.cs:wiersz 440 w WebSocketSharp.HttpBase.readHeaders(Stream stream, Int32 maxLength) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\HttpBase.cs:wiersz 131 w WebSocketSharp.HttpBase.Read[T](Stream stream, Func2 parser, Int32 millisecondsTimeout) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\HttpBase.cs:wiersz 169 --- Koniec śladu stosu wyjątków wewnętrznych --- w WebSocketSharp.HttpBase.Read[T](Stream stream, Func`2 parser, Int32 millisecondsTimeout) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\HttpBase.cs:wiersz 191 w WebSocketSharp.HttpRequest.Read(Stream stream, Int32 millisecondsTimeout) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\HttpRequest.cs:wiersz 165 w WebSocketSharp.Net.WebSockets.TcpListenerWebSocketContext..ctor(TcpClient tcpClient, String protocol, Boolean secure, X509Certificate certificate, Logger logger) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\Net\WebSockets\TcpListenerWebSocketContext.cs:wiersz 79 w WebSocketSharp.Ext.GetWebSocketContext(TcpClient tcpClient, String protocol, Boolean secure, X509Certificate certificate, Logger logger) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\Ext.cs:wiersz 555 w WebSocketSharp.Server.WebSocketServer.<>cDisplayClass8.b7(Object state) w c:\Users\dahm\Desktop\websocket-sharp-master\websocket-sharp-master\websocket-sharp\Server\WebSocketServer.cs:wiersz 636

This exception occurs even when I try different ways to generate a certificate or websocket clients. Could you tell me what is the cause of this error?

sta commented 9 years ago

Hello there,

Could you describe your environment more (e.g. OS, Web browser, etc)?

I think this issue is the same as issue #37 and #38.

A workaround that i've tested is the following (on Windows 8.1, and requires .NET 4.5).

HttpConnection.cs (for HttpServer)

    public HttpConnection (Socket socket, EndPointListener listener)
    {
      ...

      var netStream = new NetworkStream (socket, false);
      if (_secure) {
        var sslStream = new SslStream (netStream, false);
        //sslStream.AuthenticateAsServer (listener.Certificate);
        sslStream.AuthenticateAsServer (listener.Certificate, false, System.Security.Authentication.SslProtocols.Tls12, false);

        _stream = sslStream;
      }
      else {
        _stream = netStream;
      }

      ...
    }

TcpListenerWebSocketContext.cs (for WebSocketServer)

    internal TcpListenerWebSocketContext (
      TcpClient tcpClient, string protocol, bool secure, X509Certificate certificate, Logger logger)
    {
      ...

      var netStream = tcpClient.GetStream ();
      if (secure) {
        var sslStream = new SslStream (netStream, false);
        //sslStream.AuthenticateAsServer (certificate);
        sslStream.AuthenticateAsServer (certificate, false, System.Security.Authentication.SslProtocols.Tls12, false);
        _stream = sslStream;
      }
      else {
        _stream = netStream;
      }

      ...
    }

But it doesn't work for all environment. Could you try?

dhermyt commented 9 years ago

Still doesn't work after these changes. My server is a simple WPF application .NET 4.5. I am using Windows 8 (without patch to 8.1) and Google Chrome 37. As a websocket client I use this page https://www.websocket.org/echo.html. If you would like to get some more information don't hesitate to ask. This error is a blocker for my software so I really look forward for any kind of solution.

sipsorcery commented 9 years ago

I get the same error when using a self signed certificate and Chrome on Mac (haven't tested other browsers or OS). I can get around it by getting Chrome to "trust" the web socket by visiting it directly from the browser, i.e. by entering https://192.168.33.116:8081 and clicking the trust options. After that I don't get the ArgumentOutOfRange exception.

It would probably help things if the readHeaders method in the HttpBase class checked for -1 when calling ReadByte. A connection failure exception could then be thrown to give a better indication of what's gone wrong.

sta commented 9 years ago

@sipsorcery Thanks for your post.

So, do you mean that you manually set a pair of the server url and certificate to be trusted for the WebSocket in Chrome, before connecting, and then it works?

sipsorcery commented 9 years ago

In my case Chrome not trusting a self signed certificate is what caused me to get the exception in lem1x's post (although that exception could be thrown for any connection issue so people could be getting it for different things).

By getting Chrome to trust the certificate - which I did by browsing directly to the web socket and clicking past the warnings - my web socket connections started working.