Xpra-org / xpra-html5

HTML5 client for Xpra
Mozilla Public License 2.0
203 stars 55 forks source link

WebTransport #143

Closed totaam closed 2 months ago

totaam commented 2 years ago

chrome status : WebTransport

There's going to be a lot of overlap with https://github.com/Xpra-org/xpra/issues/3376

totaam commented 3 months ago

According to this SO answer, we should be able to open a WebTransport connection using a self-signed certificate with the serverCertificateHashes option.

Something like:

openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -x509 -nodes -days 10 \
    -out ./cert.pem -keyout ./key.pem -subj '/CN=Test Certificate' -addext "subjectAltName = DNS:localhost"
openssl x509 -in cert.pem | openssl dgst -sha256 -binary | openssl enc -base64 > cert-hash.b64
xpra start --bind-quic=0.0.0.0:10000  --no-daemon \
    --start=xterm -d websocket,http,quic --ssl-cert=./cert.pem --ssl-key=./key.pem 

Then this Javascript should work:

const hash = "bVBYOdvpjg5QYaOl9QZXnktoqu7XhMDiTdwbzBn6cAI=";
function base64ToArrayBuffer(base64) {
    var binaryString = atob(base64);
    var bytes = new Uint8Array(binaryString.length);
    for (var i = 0; i < binaryString.length; i++) {
        bytes[i] = binaryString.charCodeAt(i);
    }
    return bytes.buffer;
}
const wt = new WebTransport('https://127.0.0.1:10000/', {
        serverCertificateHashes: [
          {
            algorithm: 'sha-256',
            value: base64ToArrayBuffer(hash)
          }
        ]
      });
await wt.ready

Unfortunately, this raises a: WebTransportError: Opening handshake failed.. I also tried with aioquic's example http server, it also fails, showing this message:

INFO quic [69d01f836aa19fc7] Connection close received (code 0x12E, reason 199:TLS handshake failure (ENCRYPTION_HANDSHAKE) 46: certificate unknown)

Important note: do not use localhost, use 127.0.0.1 - because IPv6 breaks things, as always.

This would be extremely useful for testing, or even for deployments were the key hash can be exchanged securely through other means.


Another example here: GoogleChrome: webtransport_server.py does not use serverCertificateHashes so perhaps this is not supported by chrome?

totaam commented 2 months ago

W3C WebTransport: Authentication using Certificate Hashes

Chrome

The only test I can find actually checks that hashes don't work.. chromium w3c: server-certificate-hashes.https.any.js Despite using both the chrome command line switches and the serverCertificateHashes option, both xpra and the aioquic test server report the exact same message:

INFO quic [1673eed874a5ffe5] Connection close received (code 0x12E, reason 199:TLS handshake failure (ENCRYPTION_HANDSHAKE) 46: certificate unknown)

Firefox

Issues: Support serverCertificateHashes in the WebTransport constructor options and Webtransport: serverCertificateHashes does not work as expected Reads like this should work as of Firefox 125. Fedora 40 has Firefox 127 now, but I get WebTransport connection rejected:

Uncaught (in promise) 
WebTransportError { source: "session", streamErrorCode: null, name: "WebTransportError", message: "WebTransport connection rejected", code: 0, result: 0, filename: "", lineNumber: 0, columnNumber: 0, data: null }

And both xpra and the aioquic test server report the same sequence of events:

[509ff5d9deec30d3] Network path ('127.0.0.1', 40808) discovered
[509ff5d9deec30d3] QuicConnectionState.FIRSTFLIGHT -> QuicConnectionState.CONNECTED
[509ff5d9deec30d3] TLS State.SERVER_EXPECT_CLIENT_HELLO -> State.SERVER_EXPECT_FINISHED
[ce348454c92e82cf465d19d41aecd864c7] Network path ('127.0.0.1', 44281) discovered
[ce348454c92e82cf465d19d41aecd864c7] QuicConnectionState.FIRSTFLIGHT -> QuicConnectionState.CONNECTED
[ce348454c92e82cf465d19d41aecd864c7] TLS State.SERVER_EXPECT_CLIENT_HELLO -> State.SERVER_EXPECT_FINISHED
[509ff5d9deec30d3] Discarding epoch Epoch.INITIAL
[509ff5d9deec30d3] Connection close received (code 0x12B, reason )
[509ff5d9deec30d3] QuicConnectionState.CONNECTED -> QuicConnectionState.DRAINING
[ce348454c92e82cf465d19d41aecd864c7] Discarding epoch Epoch.INITIAL
[ce348454c92e82cf465d19d41aecd864c7] Connection close received (code 0x12B, reason )
[ce348454c92e82cf465d19d41aecd864c7] QuicConnectionState.CONNECTED -> QuicConnectionState.DRAINING
[ce348454c92e82cf465d19d41aecd864c7] Discarding epoch Epoch.HANDSHAKE
[ce348454c92e82cf465d19d41aecd864c7] Discarding epoch Epoch.ONE_RTT
[ce348454c92e82cf465d19d41aecd864c7] QuicConnectionState.DRAINING -> QuicConnectionState.TERMINATED
[509ff5d9deec30d3] Discarding epoch Epoch.HANDSHAKE
[509ff5d9deec30d3] Discarding epoch Epoch.ONE_RTT
[509ff5d9deec30d3] QuicConnectionState.DRAINING -> QuicConnectionState.TERMINATED

Safari

is the new IE - it is hopeless: web-platform-tests dashboard: server-certificate-hashes test: Can't find variable: WebTransport!

totaam commented 2 months ago

Only managed to connect by using an mkcert CA and an https context hosting the Javascript - without any serverCertificateHashes shenanigans.

My guess is that the default CSP is preventing the browser from connecting to a WebTransport endpoint unless the Javascript is also running from a secure page + maybe some more hosts restrictions.

totaam commented 2 months ago

Working as of the commit above and xpra 6.1 from git master.

To use it:


Note: using a valid certificate is a pain. I have used mkcert successfully with Firefox, but not with Chrome.. Valid letsencrypt certificates work with both.


To verify that the connection uses WebTransport instead of secure websockets, run:

xpra info | grep -i connection.type

It should show webtransport and not wss. (this requires https://github.com/Xpra-org/xpra/commit/ed03934e5271fc4b3090d8796b64b98d66ee2f7e or later version of the xpra server)