Closed hamishwillee closed 8 months ago
Also, is there any test code or example code for this. given the value is an ArrayBuffer
, I'm sure it is not as easy as:
const transport = new WebTransport(url, {
serverCertificateHashes: [
{
algorithm: "sha-256",
value: "5a155927eba7996228455e4721e6fe5f739ae15db6915d765e5db302b4f8a274",
}
],
});
This is an opportunity to improve the documentation in the spec, but this might help.
You need to think of TLS as providing a secure connection to the holder of a certificate. But TLS doesn't care beyond that, so you could be connecting to the wrong server.
In PKI, we look for a chain of signatures that connect to a trusted root. This is more or less as you describe (the key exchange part not so much, but that's TLS business). That tells the client that it is good for some name. The client also needs to check if it has the expected name.
So we have three conditions before the client considers the connection to be good:
With a hash, the client is told directly which certificate(s) is/are good. No need for the second and third checks. Instead, the client checks if the hash of the certificate is equal to one that it was given.
The hash allows the instruction to the client to be a little smaller. You don't need to supply a whole certificate of hundreds of bytes, just a small set of bytes. Collision resistance ensures that if the hash matches, it is absurdly unlikely that certificate is a different one.
Your sample code should be sufficient (assuming that someone has a certificate with that hash, of course).
Thanks @martinthomson
With a hash, the client is told directly which certificate(s) is/are good. No need for the second and third checks. Instead, the client checks if the hash of the certificate is equal to one that it was given.
I understand that given a hash and a matching certificate (from server) - the client knows it has a secure connection to a server that holds the certificate (that it knows about).
But to confirm, what is the client here? My assumption above is that it is the user agent, which is checking against hashes supplied in the constructor call to WebTransport?
[My assumption is based on thinking that there is no reason to specify the hash in the constructor to WebTransport unless something else is doing the checking. Unless this is somehow to tell the server which certificate you want it to send back. Hence the confused questions about the message flow]
Or to put it another way, I'm interested in the perspective of a javascript developer using the API. I "think" they never see a certificate. They magically get a hash from somewhere and all the work of then setting up the connection is handled by the browser.
The follow on question then is "where" they magically get the hash from. I mean, would it be that you have to connect to the app every 2 weeks to make sure you download a new set of hashes before the old ones disappear?
Your sample code should be sufficient (assuming that someone has a certificate with that hash, of course).
Thank you. So there is implicit conversion from a string to an ArrayBuffer
?
implicit conversion from a string to an ArrayBuffer?
Oh, probably not as it happens. My mistake. WebRTC accepts strings, but it looks like this one needs conversion.
How is it envisaged that the client code gets the hash(s) in the first place? It feels like a chicken and egg problem - you won't be able to download code with the latest server hashes until you have already got a TLS connection. In which case the server must have had a certificate that you can trust at some point.
Typically, there is a third-party that would act as a trusted intermediary between you.
Imagine, for instance, you have a cloud provider that can provision VMs for you. You can ask the provider to launch a virtual machine for you; the cloud provider would create a VM with a WebTransport-based SSH/RDP-like server for its certificate; the server would generate a certificate automatically, and then the cloud provider (having trusted connectivity to the VM) would connect to the server, get its certificate and report its hash via the cloud console. This means that the client now can connect directly to the VM in question via the web UI despite it not having a long-lived TLS certificate (most existing solutions require a Web-to-SSH proxy or something similar).
Thank you very much. I feel my questions have been answered. I'll leave this open in case you decide the specification requires a little more clarification.
Adding an example might be nice.
I'm updating WebTransport docs for MDN: https://github.com/mdn/content/pull/26529/files#r1182080186. The constructor option
serverCertificateHashes
documentation doesn't make much sense to me and I'm also finding https://w3c.github.io/webtransport/#certificate-hashes a little opaque.I (think) understand Web PKI:
For server certificates I think it works this way:
a. Client code "somehow" has SHA-256 hash(es) of server certificate(s) (or whatever other algorithms get added later to the spec). b. Client constructs
WebTransport
passing the hash/algorithmsIs that correct? If not, would appreciate your advice on how this actually works.
How is it envisaged that the client code gets the hash(s) in the first place? It feels like a chicken and egg problem - you won't be able to download code with the latest server hashes until you have already got a TLS connection. In which case the server must have had a certificate that you can trust at some point.