libp2p / specs

Technical specifications for the libp2p networking stack
https://libp2p.io
1.56k stars 273 forks source link

add a WebTransport spec #404

Closed marten-seemann closed 1 year ago

marten-seemann commented 2 years ago

This PR adds a basic spec for WebTransport, based on https://pl-strflt.notion.site/Enabling-WebTransport-across-the-libp2p-network-c6849c7252a1469a828a6c3e4b6abcad.

Most important things to watch out for when reviewing:

  1. The multiaddr format: The multiaddr contains the hashes of the certificates used, e.g. /ip4/1.2.3.4/udp/443/quic/webtransport/<hash1><hash2>. Is this a sane construction?
  2. We need to run a libp2p handshake on the WebTransport connection to verify peer IDs.

UPDATE 2022-07-26: Updated the link to the Notion page. I was mistaken in believing that the previous link was already public.

marten-seemann commented 2 years ago

I updated the spec, incorporating the ideas of @Stebalien and @Kubuxu for securing the connection and avoiding double-encryption:

  1. I introduced a /certhash multiaddr component, which can be repeated to transmit multiple certificate hashes.
  2. We now use Noise to perform the libp2p handshake, and transmit the list of certificate hashes the client was willing to accept as (unencrypted, but integrity-protected) payload of the first handshake message.
  3. The server verifies that it possesses certificates matching ALL of the certificate hashes.
  4. This also means that we won't be able to accept CA-signed certificates any more, as the Noise handshake described above is needed to tie the outer (WebTransport, TLS) connection to the Noise handshake. This simplifies the spec.
Kubuxu commented 2 years ago

If we really wanted we could accept CA-signed certs but as self-signed certs are the primary use case, we might as well use just self-signed.

SgtPooki commented 2 years ago

I introduced a /certhash multiaddr component, which can be repeated to transmit multiple certificate hashes.

Can we convert the '/certhash' pairs into an IPLD structure and do something like '/certhashs/' or something similar?

MarcoPolo commented 2 years ago

I introduced a /certhash multiaddr component, which can be repeated to transmit multiple certificate hashes.

Can we convert the '/certhash' pairs into an IPLD structure and do something like '/certhashs/' or something similar?

I don't think we'd want to do that since then we'd have to fetch the certhash someway (since we only have the cid). Also I'm not sure what we would gain from the extra overhead of having a struct here. We also don't want to introduce an IPLD dependency for every implementation that wants to add this.

Is there something I'm missing?

SgtPooki commented 2 years ago

Is there something I'm missing?

The CID shouldn't require lookup if it's an identity CID, other than that, probably not? ¯\_(ツ)_/¯

Kubuxu commented 2 years ago

Interesting idea of using Noise Prologue instead of handshake payload data: https://github.com/libp2p/specs/pull/412/files#r931163931 if we don't need to actually send this data.

marten-seemann commented 2 years ago

Interesting! Any suggestion what exactly to put in the prologue? Unfortunately, when using multiple certhashes (as we will do), the browser won't know which of the certificates was accepted.

Menduist commented 2 years ago

To use this technique, you need to have a value known by the server & the client, where each of them has an impact on the value, before the Noise handshake begins. (to safely identify one specific session)

So in webrtc case, concatenating both certificates does the trick, in webtransport case, I don't know if there is something similar applicable

Kubuxu commented 2 years ago

Interesting! Any suggestion what exactly to put in the prologue? Unfortunately, when using multiple certhashes (as we will do), the browser won't know which of the certificates was accepted.

You are right, I forgot about this caveat. In this situation, I don't think there is a nice way to use the Noise Prologue.

marten-seemann commented 2 years ago

If https://github.com/w3c/webtransport/issues/411 is implemented, we could use that key exporter to generate a unique value tied to the TLS session, which could be used as the Noise prologue.

marten-seemann commented 2 years ago

Thank you everyone for the great discussions on this PR!

We've shipped (experimental) WebTransport support based on this specification in go-libp2p v0.23.

I've resolved all remaining nits in the specification. Would be grateful for another round of review and many approvals :)

marten-seemann commented 1 year ago

Thank you for this in-depth review, @elenaf9!

I rewrote the "Certificates" section to allow the use of CA-signed certificates.

marten-seemann commented 1 year ago

Thank you to everyone involved here! This was a big effort, and we now have a decent spec, implemented and released by go-libp2p, with another implementation in js-libp2p demonstrating interoperability.

Given that this PR has received 2 approvals from members of the libp2p team at PL, I'm going to merge it now. This does NOT mean that this spec is perfect - both editorial as well as protocol changes are still possible via PRs to this repo.

mxinden commented 1 year ago

:rocket: big step for the project!

Small nit, can you add an entry to https://github.com/libp2p/specs#protocols?