locked
How to use UpgradeToSslAsync over a proxy server using a stream socket.

    Question

  • I want the following scenario in TLS connection.

    StreamSocket --------TLS-------->HTTPproxyserver   -----HTTPS------->RemoteHost.

    Here is my process:

    1.Connect with the proxy server using streamsocket ->ConnectAsync() method.

    StreamSocket-------------tcp------------->HTTPproxyserver               RemoteHose

    2.Send HTTP connect request to Remote server via proxy.Proxy server then connect with remote Server.

    StreamSocket----------tcp---------->HTTPproxyserver   --------HTTP------- >RemoteHost

    3.After 1 & 2 is successful we try to upgrade into TLS using  StreamSocket->UpgradeToSslAsync(SocketProtectionLevel::Ssl,ref new HostName(remoteHost)) )

    We used RemoteHostname as Validation Host name.

    upgrading is failing with the following exception:

    *The token supplied to the function is invalid*

    Now my question is that ,

    1.Is it possible to upgrade a streamsocket to ssl if there is a proxyserver in between ?

    if no, is there any other way i can get this functionality?

    2.What should i use validation host name in UpgradeToSslAsync().Proxy host name or remote host name.?

    i also try with proxy username as validation host name.this is also getting exception.

    Note : If we dont use any proxy in the middle ,we can do direct TLS connection with remote host.Even upgrade to ssl also works fine if there is no proxy.


    • Edited by Fahad_Ahmed Friday, November 1, 2013 6:35 AM wasnt undestandable enough
    Friday, November 1, 2013 6:31 AM

Answers

  • Yes, I can see the FIN packet right after the Client Hello request. However, I cannot reproduce the same behavior when performing the following logic:

    - Create a StreamSocket

    - Call StreamSocket.ConnectAsync(proxy name, proxy port)

    - Write the Connect request using StreamSocket.WriteAsync(connect request) & FlushAsync()

    - Read the Connect response using StreamSocket.ReadAsync()

    - Call StreamSocket.UpgradeToSslAsync(protection level, remote host name)

    - The Protection Level is set to Tls1.

    - Once the UpgradeToSslAsync is successful, I send a HTTP GET request by performing a StreamSocket.OutputStream.WriteAsync() followed by FlushAsync().

    I know you want to send some "raw" bytes and not a HTTP request, but the point here is that UpgradeToSslAsync is successful and everything after the upgrade is really not that important.

    - If the WriteAsync is successful, I call ReadAsync() where I see the 200 OK response.

    Here's what I see when I collect a Network trace. To understand your problem, if you can share your demo project that will throw some more light on the issue.


    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    • Marked as answer by Fahad_Ahmed Friday, November 8, 2013 7:34 PM
    Thursday, November 7, 2013 8:50 PM
    Moderator

All replies

  • May I ask why are you trying to implement the HTTP Protocol yourself? The scenario that you have described above is calls SSL/TLS Tunneling.

    The Windows.Web.Http.HttpClient class that is available already implements the HTTP protocol for you and does all the hard work underneath.

    For a StreamSocket, when you UpgradeToSSLAsync(), the SSL certificate validation etc will be performed based on the remote server name that you provide, and in your proxy case, it will be the proxy address, so the validation will fail. You should really consider using the new Windows.Web.Http.HttpClient class that abstracts this implementation details from the application.


    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    • Marked as answer by Fahad_Ahmed Saturday, November 2, 2013 6:43 AM
    • Unmarked as answer by Fahad_Ahmed Monday, November 4, 2013 4:04 AM
    Friday, November 1, 2013 10:07 PM
    Moderator
  • We find HTTP client works with HTTP server .It works for only with HTTP protocol.If there is a proxy in between it works but only for HTTP or HTTPs.

    We are actually trying to Relay data(not only HTTP) through a proxy to a remote server that can take TCP/TLS connection.

    We have been able to relay data through proxy using TCP.But failing to do it for TLS.

    We are been able to do,

    client------TCP(data)----->Proxy-----TCP(forwarding data) ---->RemoteServer(can take TCP/TLS connection).

    But our ultimate goal,

    client------TLS(data)----->Proxy-----TLS(forwarding data) ----->RemoteServer(can take TLS connection).

    HTTP client connects with Uri.But we want to connect with remote IP and Port.

    We also look on streamwebsocket and find it only work with web server and take Uri for connection.

    Is it possible to relay data(not only HTTP) in TLS protocol over a proxy server in windows RT platform ?

    Monday, November 4, 2013 4:35 AM
  • Can you collect a network trace when trying to use StreamSocket.UpgradeToSslAsync and share it via SkyDrive? That should atleast show the traffic that leads to the "The token supplied to the function is invalid" error that you are seeing.

    When you call UpgradeToSslAsync() and provide the validationHostName parameter as the remote host that is sitting behing the proxy, the approach should work. Since you are getting a failure, I want to check what TLS protocol version is being negotiated.

    Does your remote server implement the TLS 1.2 protocol?


    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    Tuesday, November 5, 2013 1:02 AM
    Moderator
  • Thanx for the reply.

    My Remote Server is Running TLSv.1.1.I  attached image of the pcap

    here,

    client = 192.168.0.175

    proxy server= 192.168.0.240

    remoteTLSserver = 202.126.123.141

    Capture of successful try , client -----TLS --------->remoteTLSserver

    Here its the capture of failure try,

    Cleint-------TLS---->Proxy----TLS----->RemoteTLSServer

    ( i used RemoteServers(TLS) HostName  in upgradetoSSL as validation name).

    Here,client is sending fin after client Hello(no idea Why?)

    Note:

    In TCPdump we find that,

    If initial TCP connections remoteHostName(which is proxy server) andValidationHostName(which is Remote TLS server) is different, Client Hello is send with TLSv1 protocol and [Fin,Ack] is send after client Hello.

    In successful case(no proxy), initial TCP connections remoteHostName and validation host name is same and client hello is send with ssl protocol.

    Download link for TCPdump:

    download from here

    thanx






    • Edited by Fahad_Ahmed Wednesday, November 6, 2013 7:36 AM correction
    Tuesday, November 5, 2013 7:07 AM
  • Yes, I can see the FIN packet right after the Client Hello request. However, I cannot reproduce the same behavior when performing the following logic:

    - Create a StreamSocket

    - Call StreamSocket.ConnectAsync(proxy name, proxy port)

    - Write the Connect request using StreamSocket.WriteAsync(connect request) & FlushAsync()

    - Read the Connect response using StreamSocket.ReadAsync()

    - Call StreamSocket.UpgradeToSslAsync(protection level, remote host name)

    - The Protection Level is set to Tls1.

    - Once the UpgradeToSslAsync is successful, I send a HTTP GET request by performing a StreamSocket.OutputStream.WriteAsync() followed by FlushAsync().

    I know you want to send some "raw" bytes and not a HTTP request, but the point here is that UpgradeToSslAsync is successful and everything after the upgrade is really not that important.

    - If the WriteAsync is successful, I call ReadAsync() where I see the 200 OK response.

    Here's what I see when I collect a Network trace. To understand your problem, if you can share your demo project that will throw some more light on the issue.


    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    • Marked as answer by Fahad_Ahmed Friday, November 8, 2013 7:34 PM
    Thursday, November 7, 2013 8:50 PM
    Moderator
  • Thank you for the reply.
    I have been able to resolve the problem.

    First i tried to do in  the same way you did it.
    But i get the exception:
    WinRT information: I/O operations in progress. UpgradeToSslAsync is only available when there are no I/O operations in progress.

    Then i omit the call of my receive operation loop(LoadAsync() and then read from buffer) to avoid I/O exception.Then i get the exception:
    WinRT information: The token supplied to the function is invalid

    I solved this problem by setting InputStreamOptions::Partial  for the Inputstream
    {
        reader = ref new DataReader(tcpSocket->InputStream);
        reader->InputStreamOptions =      Windows::Storage::Streams::InputStreamOptions::Partial;
    }


    I want to mention another issue,

    Different forum post says to stop write and read operation during up-gradation.Microsoft sample code provided for streamsocket continuously take attempt to read from input buffer   in  a task .

    So whats the best way to write some data ,then read some data and  then upgrade the socket to ssl?

    or

    Whats the best way to avoid the following exception ?

    WinRT information: I/O operations in progress. UpgradeToSslAsync is only available when there are no I/O operations in progress.

    Here you mention  about ReadAsync() option.But i don't find any sample over internet how to use it properly with streamsocket?

    Thank you very much for your nice support.

    • Edited by Fahad_Ahmed Friday, November 8, 2013 5:27 PM
    Friday, November 8, 2013 5:16 AM
  • When you send the HTTP Connect request to the proxy, you will need to completely read the response before you call UpgradeToSslAsync(). If there is a pending read operation in progress, you cannot just call UpgradeToSslAsync in the middle of a read/write.

    One simple approach is to use code similar to this to read/ drain the 200 OK Connection Established response before calling UpgradeToSslAsync.

                    /// Consume the HTTP Connect response and then try to upgrade
                    byte[] responseBytes = new byte[1024];
                    Array.Clear(responseBytes, 0, responseBytes.Length);
                    IInputStream inputStream = socket.InputStream;
                    await inputStream.ReadAsync(responseBytes.AsBuffer(), (uint)responseBytes.Length, InputStreamOptions.Partial);
                    /// Now you can call UpgradeToSslAsync...
    


    Windows Store Developer Solutions, follow us on Twitter: @WSDevSol|| Want more solutions? See our blog

    • Proposed as answer by B0L Friday, April 18, 2014 3:46 AM
    Friday, November 8, 2013 7:54 PM
    Moderator
  • Thank you very much for your patience.

    You reply  was very helpful for me.I guess it will be helpful for others as well.

    Thank you for being so nice .

    Saturday, November 9, 2013 12:03 AM