NativeWebSocket icon indicating copy to clipboard operation
NativeWebSocket copied to clipboard

wss protocol does not work when build on UWP

Open salinhard opened this issue 5 years ago • 12 comments

I'm using your great library for implement websockets on Hololens. If I use a ws protocol, it works on Unity Editor and Hololens. If I use wss, it works on Unity Editor but does not work on Hololens.

Seems a certificate error, because I get this error on the Hololens log: Curl error 51: Cert verify failed: UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED

Here the errors I got:

A call to SSPI failed, see inner exception.

Mono.Security.Interface.TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED at Mono.Unity.Debug.CheckAndThrow (Mono.Unity.UnityTls+unitytls_errorstate errorState, Mono.Unity.UnityTls+unitytls_x509verify_result verifyResult, System.String context, Mono.Security.Interface.AlertDescription defaultAlert) [0x00036] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 at Mono.Unity.UnityTlsContext.ProcessHandshake () [0x00082] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 at Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status) [0x0003e] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 at (wrapper remoting-invoke-with-check) Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake(Mono.Net.Security.AsyncOperationStatus) at Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) [0x00006] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 at Mono.Net.Security.AsyncProtocolRequest+<ProcessOperation>d__24.MoveNext () [0x000ff] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in :0 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in :0 at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000] in :0 at Mono.Net.Security.AsyncProtocolRequest+<StartOperation>d__23.MoveNext () [0x0008b] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0

at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 at Mono.Net.Security.MobileAuthenticatedStream+<ProcessAuthentication>d__47.MoveNext () [0x00254] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in :0 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in :0 at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000] in :0 at System.Net.WebSockets.WebSocketHandle+<ConnectAsyncCore>d__24.MoveNext () [0x00199] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0

System.Security.Authentication.AuthenticationException

at System.Net.WebSockets.WebSocketHandle+<ConnectAsyncCore>d__24.MoveNext () [0x00391] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in :0 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in :0 at System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () [0x00000] in :0 at System.Net.WebSockets.ClientWebSocket+<ConnectAsyncCore>d__16.MoveNext () [0x000d1] in <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in :0 at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in :0 at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in :0 at System.Runtime.CompilerServices.TaskAwaiter.GetResult () [0x00000] in :0 at NativeWebSocket.WebSocket+<Connect>d__19.MoveNext () [0x0005a] in C:\Users\manuel\development\unityProjects\NativeWebsocket\Assets\Scripts\WebSocket.cs:306

salinhard avatar Sep 23 '19 09:09 salinhard

Hi @salinhard, could it be a certificate issue? Can you confirm on this SSL reports if yours is valid? https://www.ssllabs.com/ssltest/

A recurring SSL configuration issue I see (and do myself sometimes) is not using the fullchain.pem certificate in the server-side. (If you're using only cert.pem, you should consider using fullchain.pem instead!)

Cheers

endel avatar Sep 23 '19 17:09 endel

Hi @endel I checked on https://www.ssllabs.com/ssltest/ and my certificate seems valid, I'm also trying to connect to wss://echo.websocket.org and does not work.

Did you try some wss that is working?

salinhard avatar Sep 24 '19 09:09 salinhard

Hello. I have a similar error. The certificate is verified and working. TlsException: Handshake failed - error code: UNITYTLS_INTERNAL_ERROR, verify result: UNITYTLS_X509VERIFY_FLAG_NOT_TRUSTED Mono.Unity.Debug.CheckAndThrow (Mono.Unity.UnityTls+unitytls_errorstate errorState, Mono.Unity.UnityTls+unitytls_x509verify_result verifyResult, System.String context, Mono.Security.Interface.AlertDescription defaultAlert) (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) Mono.Unity.UnityTlsContext.ProcessHandshake () (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake (Mono.Net.Security.AsyncOperationStatus status) (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) (wrapper remoting-invoke-with-check) Mono.Net.Security.MobileAuthenticatedStream.ProcessHandshake(Mono.Net.Security.AsyncOperationStatus) Mono.Net.Security.AsyncHandshakeRequest.Run (Mono.Net.Security.AsyncOperationStatus status) (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) Mono.Net.Security.AsyncProtocolRequest+<ProcessOperation>d__24.MoveNext () (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) --- End of stack trace from previous location where exception was thrown --- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at :0) System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () (at :0) Mono.Net.Security.AsyncProtocolRequest+<StartOperation>d__23.MoveNext () (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) Rethrow as AuthenticationException: A call to SSPI failed, see inner exception. System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at :0) Mono.Net.Security.MobileAuthenticatedStream+<ProcessAuthentication>d__47.MoveNext () (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) --- End of stack trace from previous location where exception was thrown --- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at :0) System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () (at :0) System.Net.WebSockets.WebSocketHandle+<ConnectAsyncCore>d__24.MoveNext () (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) Rethrow as WebSocketException: Unable to connect to the remote server System.Net.WebSockets.WebSocketHandle+<ConnectAsyncCore>d__24.MoveNext () (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) --- End of stack trace from previous location where exception was thrown --- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at :0) System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.ConfiguredTaskAwaitable+ConfiguredTaskAwaiter.GetResult () (at :0) System.Net.WebSockets.ClientWebSocket+<ConnectAsyncCore>d__16.MoveNext () (at <0d3e94ab2a1c4d2a8582ccee7031f5c6>:0) --- End of stack trace from previous location where exception was thrown --- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at :0) System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.GetResult () (at :0) NativeWebSocket.WebSocket+<Connect>d__19.MoveNext () (at Assets/Scripts/Network/WebSocket.cs:297) --- End of stack trace from previous location where exception was thrown --- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at :0) System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) (at :0) System.Runtime.CompilerServices.TaskAwaiter.GetResult () (at :0) Network.Core.SocketClient+<StartClient>d__7.MoveNext () (at Assets/Scripts/Network/SocketClient.cs:67) --- End of stack trace from previous location where exception was thrown --- System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () (at :0) System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.<ThrowAsync>b__6_0 (System.Object state) (at :0) UnityEngine.UnitySynchronizationContext+WorkRequest.Invoke () (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnitySynchronizationContext.cs:115) UnityEngine.UnitySynchronizationContext:ExecuteTasks()

wivanw avatar Nov 12 '19 12:11 wivanw

Hi @wivanw are you also using UWP? On which platform are you getting this error?

endel avatar Nov 12 '19 13:11 endel

The problem was incorrect protocol settings: webSocketServer.SslConfiguration.EnabledSslProtocols = System.Security.Authentication.SslProtocols.Ssl3; WebGL platform. Sorry for your time.

wivanw avatar Nov 12 '19 13:11 wivanw

In fact, the error was deeper. The solution is described: https://issuetracker.unity3d.com/issues/error-of-tlsexception-when-system-dot-net-dot-http-dot-dll-is-used-for-http-in-the-editor Only now my WebSockets have worked correctly.

wivanw avatar Nov 12 '19 14:11 wivanw

Thanks for the details @wivanw, this is probably going to be helpful for more people having this issue!

endel avatar Nov 12 '19 14:11 endel

I’ll supplement it. Check if you generated the certificate correctly. Although this stub works on some platforms, it does not work in WebGL. The error was precisely in the fact that the certificate was generated at the wrong level of the domain address. Here is the code that will make it easier for you to find certificate errors:

        ServicePointManager.ServerCertificateValidationCallback =
            (sender, certificate, chain, sslPolicyErrors) =>
            {
                bool isOk = true;
                // If there are errors in the certificate chain, look at each error to determine the cause.
                if (sslPolicyErrors != SslPolicyErrors.None)
                {
                    for (int i = 0; i < chain.ChainStatus.Length; i++)
                    {
                        if (chain.ChainStatus[i].Status != X509ChainStatusFlags.RevocationStatusUnknown)
                        {
                            chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EntireChain;
                            chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
                            chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 1, 0);
                            chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllFlags;
                            bool chainIsValid = chain.Build((X509Certificate2) certificate);
                            Debug.Log($"ChainIsValid: {chainIsValid}");
                            if (!chainIsValid)
                            {
                                isOk = false;
                            }
                        }
                    }
                }

                return isOk;
            };
        ServicePointManager.CertificatePolicy = new StubCertificatePolicy();
    private enum CertificateProblem : uint
    {
        None = 0x00000000,
        CertExpired = 0x800B0101,
        CertValidityPeriodNesting = 0x800B0102,
        CertRole = 0x800B0103,
        CertPathLenConst = 0x800B0104,
        CertCritical = 0x800B0105,
        CertPurpose = 0x800B0106,
        CertIssuerChaining = 0x800B0107,
        CertMalformed = 0x800B0108,
        CertUntrustedRoot = 0x800B0109,
        CertChaining = 0x800B010A,
        CertRevoked = 0x800B010C,
        CertUntrustedTestRoot = 0x800B010D,
        CertRevocationFailure = 0x800B010E,
        CertCnNoMatch = 0x800B010F,
        CertWrongUsage = 0x800B0110,
        CertUntrustedCa = 0x800B0112,

        //https://docs.microsoft.com/ru-ru/office/troubleshoot/error-messages/generic-trust-failure-(0x800b010b)-error
        GeneralFailureOfTrust = 0x800B010B
    };

    private class StubCertificatePolicy : ICertificatePolicy
    {
        private const bool DefaultValidate = true;

        public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request,
            int certificateProblem)
        {
            if ((CertificateProblem) certificateProblem != CertificateProblem.None)
            {
                Debug.Log($"Certificate Problem with accessing {request?.RequestUri}");
                Debug.Log($"Problem code 0x{certificateProblem:X8},");
                Debug.LogError(GetProblemMessage((CertificateProblem) certificateProblem));
                return true;
            }

            return DefaultValidate;
        }

        private static string GetProblemMessage(CertificateProblem problem)
        {
            var problemMessage = string.Empty;
            var problemCodeName = Enum.GetName(typeof(CertificateProblem), problem);
            problemMessage = !string.IsNullOrEmpty(problemCodeName)
                ? $"{problemMessage} Certificate problem:{problem}  code:{problemCodeName}"
                : "Unknown Certificate Problem";

            return problemMessage;
        }
    }

wivanw avatar Nov 19 '19 08:11 wivanw

Hey @wivanw @endel - thank you for your work in exploring this issue.

I believe I have hit the same problem. When we run our app through unity, or side loaded onto the Oculus Rift it works properly utilizing the NativeWebSocket library. When we build and upload to Oculus and install that way, the Websocket is no longer able to connect.

@wivanw - where did you apply that code in your most recent reply?

Thank you!

Roar1827 avatar Apr 26 '20 01:04 Roar1827

Hey @wivanw @endel - thank you for your work in exploring this issue.

I believe I have hit the same problem. When we run our app through unity, or side loaded onto the Oculus Rift it works properly utilizing the NativeWebSocket library. When we build and upload to Oculus and install that way, the Websocket is no longer able to connect.

@wivanw - where did you apply that code in your most recent reply?

Thank you!

It took a long time until we realized that this library is based on another 4 years ago. It is very unstable and unsuitable for product release. We use Best HTTP2 which works like a watch. You can also use the libraries of both the server and the client pulled from Photone engyne assets.

wivanw avatar Apr 27 '20 07:04 wivanw

Thank you for the reply @wivanw - I appreciate you taking the time.

Roar1827 avatar Apr 27 '20 12:04 Roar1827