Search Unity

  1. Are you interested in providing feedback directly to Unity teams? Sign up to become a member of Unity Pulse, our new product feedback and research community.
    Dismiss Notice

Websockets over TLS 1.2 cause an unexpected exception with some endpoints

Discussion in '2018.2 Beta' started by davidtruchon, Apr 19, 2018.

  1. davidtruchon

    davidtruchon

    Joined:
    Jun 25, 2017
    Posts:
    6
    The following code returns a 403 forbidden error on Microsoft .Net 4.7.1 runtime.

    On Unity the following code returns the following exception :

           
    var _webSocket = new ClientWebSocket();
    try
    {
    _webSocket.ConnectAsync(new Uri("wss://<ID>.iot.<REGION>.amazonaws.com/mqtt"), CancellationToken.None)
    .ConfigureAwait(false)
    .GetAwaiter()
    .GetResult();
    }
    catch (Exception e)
    {
    Debug.LogError(e);
    }


    System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server
    at System.Net.WebSockets.WebSocketHandle+<ParseAndValidateConnectResponseAsync>d__28.MoveNext () [0x00107] in <4ca7fa06156443beb88ec302e6e9783c>:0
    --- End of stack trace from previous location where exception was thrown ---


    This example's URI is left unsigned on purpose as it does not change the result of the test.

    Some endpoints works without issues such as this public test endpoint wss://echo.websocket.org.
    The issue could be specific to AWS but is limited to the Unity environment as a successful connection can be made using the Microsoft .Net runtime.
     
    faviann likes this.
  2. andreasreich

    andreasreich

    Unity Technologies

    Joined:
    Sep 24, 2017
    Posts:
    55
    Not sure if it is the same issue, but we have identified an issue with some failing TLS1.2 handshakes which I'm investigating right now. I'll try to keep this thread updated.
     
  3. andreasreich

    andreasreich

    Unity Technologies

    Joined:
    Sep 24, 2017
    Posts:
    55
    Oh false alarm on the other project I had - there it worked as expected with the new Mono runtime (.Net 4.x equivalent).

    Since you're writing that you already use the new runtime, could you please file a bug with a repro-project? I have some trouble reproducing the issue. Thank you!
     
  4. davidtruchon

    davidtruchon

    Joined:
    Jun 25, 2017
    Posts:
    6
    I filed a bug report with a repro-project. Case number : 1028147
     
    LeonhardP and andreasreich like this.
  5. greenland

    greenland

    Joined:
    Oct 22, 2005
    Posts:
    205
    This might be the wrong spot, but I've also got WebSocketExceptions. It claims unknown host and no route to host... but the host domain is up and running... is there any version of Unity where TLS works correctly? It's listed as a new feature, but I'm using Firebase, which has been around a while, which tries to make use of it.
     
  6. andreasreich

    andreasreich

    Unity Technologies

    Joined:
    Sep 24, 2017
    Posts:
    55
    Alright, I try to give some more background to clear out any confusion this might have caused. :)

    UnityWebRequest:
    Supported TLS1.2 and had system certificate store verification on most platforms. Now both works everywhere.

    Old scripting runtime:
    We had and have TLS1.0 support but no system certificate store verification.

    New scripting runtime:
    Pre 2018.2 we had only what Mono called their legacy support and some fixes here and there but we didn't want to support anything officially.
    Now in 2018.2 we implemented a new internal abstraction that forwards to different backends depending on the platform. Plus we no longer include our own certificate list for editors and can verify certificates against the platform specific certificate stores directly.
    Other from a few internal direct uses, we wired this to Mono (as a "MonoTlsProvider") as well as in curl (and thus in UnityWebRequest on the platforms where it is based on curl). We didn't touch any higher-level things like the stuff in System.Net and verified our integration pretty much only by using System.Net.Security.SslStream which is what all the other things are based on. That went very well, but needless to say that these issues might be related nonetheless.


    I haven't looked into @davidtruchon's issue too deeply yet, but I can tell that everything goes smoothly in the backend. So probably it is a (preexisting?) issue in Mono that it doesn't fill out the exception correctly. Both on Microsoft .Net 4.7.1 and our Mono runtime I get a System.Net.WebSockets.WebSocketException that has "Unable to connect to the remote server" in it but only the Microsoft one provides the additional info on the 403 error. Need to figure out if Mono is actually able to do that...

    @greenland: I can't say anything on Firebase as I don't know which APIs it uses and what platforms you tried it on.
     
    Last edited: Apr 23, 2018
  7. andreasreich

    andreasreich

    Unity Technologies

    Joined:
    Sep 24, 2017
    Posts:
    55
    @davidtruchon After some digging I found out the the behavior you're getting is identical to what .Net Core 2.0 does which is where our (and the most current official) Mono version has its implementation from.

    If you want to check the details yourself:
    • The place that throws your exception and ignores any HTTP error code
    • Code changed quite a lot in Core 2.1, but I outcome looks the same to me (haven't tested it though)
    So I don't think this is actually a bug, but works as intended. You can of course file a bug against corefx 2.0/2.1 for better compliance with .Net Framework

    @greenland: You mentioned that you're getting exceptions as well, can give more detail?
     
    Last edited: Apr 23, 2018
  8. greenland

    greenland

    Joined:
    Oct 22, 2005
    Posts:
    205
    Thanks, andreasreich.
    I've included a bit from the console... but I've now found some source on Google's github that makes me think that the Unity Firebase documentation may be inaccurate or incomplete. I'm going to check that out and report back if I am, in fact, using it correctly... so, false alarm, maybe.
    Code (CSharp):
    1.  
    2. 4/24/2018 12:27:17 AM [Error] WebSocket: ws_0 - WebSocketException during handshake
    3. Firebase.Database.Internal.TubeSock.WebSocketException: unknown host: redacted.firebaseio.com ---> System.Net.Sockets.SocketException: No route to host
    4.   at System.Net.Sockets.Socket.Connect (System.Net.EndPoint remoteEP) [0x000b6] in <4ca7fa06156443beb88ec302e6e9783c>:0
    5.   at System.Net.Sockets.TcpClient.Connect (System.Net.IPEndPoint remoteEP) [0x00033] in <4ca7fa06156443beb88ec302e6e9783c>:0
    6.   at Firebase.Database.Internal.TubeSock.WebSocket.CreateSocket () [0x000f3] in <8cc1ef70e8084ebcad7aac4d9bf43a94>:0
    7.    --- End of inner exception stack trace ---
    8.   at Firebase.Database.Internal.TubeSock.WebSocket.CreateSocket () [0x0011e] in <8cc1ef70e8084ebcad7aac4d9bf43a94>:0
    9.   at Firebase.Database.Internal.TubeSock.WebSocket.RunReader () [0x0001b] in <8cc1ef70e8084ebcad7aac4d9bf43a94>:0
    10. UnityEngine.Debug:LogError(Object)
    11. Firebase.Platform.FirebaseLogger:LogMessage(PlatformLogLevel, String)
    12. Firebase.Unity.UnityLoggingService:LogMessage(PlatformLogLevel, String)
    13. Firebase.Database.Internal.Logging.DefaultLogger:Error(String, String)
    14. Firebase.Database.Internal.Logging.DefaultLogger:OnLogMessage(Level, String, String, Int64)
    15. Firebase.Database.Internal.Logging.LogWrapper:Error(String, Exception)
    16. Firebase.Database.Internal.TubeSock.WebSocket:LogError(String, Exception)
    17. Firebase.Database.Internal.TubeSock.WebSocket:RunReader()
    18. Firebase.Database.Internal.TubeSock.Runnable101:Run()
    19. Google.Sharpen.Thread:InternalRun()
    20. System.Threading.ThreadHelper:ThreadStart()
    21.  
     
  9. davidtruchon

    davidtruchon

    Joined:
    Jun 25, 2017
    Posts:
    6
    @andreasreich It is the same exception but I think it throws for a different reason. When authenticating my request it connects fine on both core 2.0 and net framework 4.7.1 but fail on Unity with the exception I posted above.

    I have yet to find another endpoint with the bug beside AWS-IOT which lead me to believe it specific to how AWS handle the protocol.

    I found out AWS enforce the RFC TLS ALPN extension, is it supported by Mono/Unity?
     
  10. andreasreich

    andreasreich

    Unity Technologies

    Joined:
    Sep 24, 2017
    Posts:
    55
    No, we don't have ALPN support. Support for it is being added in .Net Core 2.1, see here. So I wouldn't expect us to adopt this too soon, almost certainly not before it into .Net Standard.

    If you find an example where you get an exception in .Net4.7.1 or Corefx2, but none (or a distinctively different one) with Unity I'm of course happy to have a another look. But for the bugreport you've submitted things seem to be fairly clear to me now as I pointed out above.

    There is however another bug I have identified and fixed today: Any request that tries to read/write more than 16kb would either fail or get stuck (depending used api). This will be fixed in one of the upcoming betas (can't promise that it's the next one). So maybe you're running into that.
     
  11. xortrox

    xortrox

    Joined:
    Feb 13, 2011
    Posts:
    21
  12. davidtruchon

    davidtruchon

    Joined:
    Jun 25, 2017
    Posts:
    6
    I submitted a better example representing the use case we're trying to solve.

    Here's a summary of the report.

    ---
    Case : 1031144

    Websocket over TLS with mqtt fails connection during handshake.

    The example has been tested on with Microsoft .Net 4.7.1,Core 2.0 and Unity. It connects fine on all platforms but Unity.

    So the example is using the library MQTTnet but I have a strong suspicion it is besides the point. Reason being:

    1) It is not a custom websocket implementation. It uses the implementation given by whichever framework it runs on. (in opposition to SuperSocket and co.)
    2) We get the same errors when only connecting a pure TLS 1.2 Websocket without any subprotocols specified. This leads us to believe that the handshake fails before even the specifics of the library kicks in to handle the subprotocol.

    For reference here is a Github link referencing the line where a .Net websocket breaks down in the MQTT lib:
    https://github.com/chkr1011/MQTTnet...d/Implementations/MqttWebSocketChannel.cs#L76
    ---

    If we can provides you any forms of additional assistance let us know; it's our last roadblock in regards to some importants parts of our project.
     
    MechEthan likes this.
  13. xortrox

    xortrox

    Joined:
    Feb 13, 2011
    Posts:
    21
    This could potentially happen if the server does not serve a specifically requested SubProtocol, as well as if the certificates are not working as they should.

    wss://echo.websocket.org
    Seems to be serving "Sec-Websocket-Version: 13" in chrome, so if you are able to connect to that, then you must also ensure that your endpoint is serving the same version I suppose. (I think this would be WebSocket.SubProtocol)

    I had a similar problem and it turns out Unity beta 2018.2 solved it for me; I wasn't able to connect to my WebSocket server through wss:// until I got 2018.2b.
     
  14. davidtruchon

    davidtruchon

    Joined:
    Jun 25, 2017
    Posts:
    6
    @andreasreich Can you tell if I am running into the bug you mentioned based on my new example project? (case 1031144)
     
  15. andreasreich

    andreasreich

    Unity Technologies

    Joined:
    Sep 24, 2017
    Posts:
    55
    I had quick spin with it and checked for large packages that would be affected. None there, so must be a different issue. I have quite a bit on my plate right now so I'll probably won't come back to it until QA had deeper look.
     
  16. davidtruchon

    davidtruchon

    Joined:
    Jun 25, 2017
    Posts:
    6
    It ended up being a compatibility issue when using .Net Sockets + Aws IOT Sigv4 + Xamarin. A slight difference of header is probably causing the Sigv4 signature to mismatch, nobody has figured it out yet. I solved my issue by using a custom web socket implementation as mentioned in this Github's issue https://github.com/chkr1011/MQTTnet/issues/211
    Thanks for pointing me in the right direction!
     
    andreasreich and MechEthan like this.
unityunity