Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webrtc/: Add libp2p WebRTC browser-to-server spec #412

Merged
merged 135 commits into from Nov 9, 2022
Merged
Changes from 38 commits
Commits
Show all changes
135 commits
Select commit Hold shift + click to select a range
9677aa2
webrtc/: Add libp2p WebRTC specification
mxinden May 11, 2022
968d127
webrtc/: Document RTCCertificate#getFingerprints
mxinden May 17, 2022
64a3dff
webrtc/: Extend protocol flow
mxinden May 17, 2022
7dfcca1
webrtc/: Mention SDP exchange through relay and DCUtR
mxinden May 17, 2022
28e341b
webrtc/: Stress that A can build B's SDP offer locally
mxinden May 18, 2022
b3bd981
webrtc/: Add B's peer ID to B's multiaddr
mxinden May 18, 2022
dc6fb4e
webrtc/: Add FAQ section
mxinden May 19, 2022
9728e22
webrtc/: Do additional auth handshake to prevent replay attack
mxinden May 24, 2022
13f6aaa
webrtc/: Differentiate in Browser->Server and Browser->Browser
mxinden Jun 1, 2022
7ec96db
webrtc/: Document open question of B learning A's fingerprint
mxinden Jun 1, 2022
5f5fd60
webrtc/: Detail generic RTCPeerConnection creation
mxinden Jun 1, 2022
84d4c41
webrtc/: Describe address scheme
mxinden Jun 1, 2022
9790d1a
webrtc/: Document open question of B learning A's fingerprint
mxinden Jun 1, 2022
4c6320e
webrtc/: Fix outdated multiaddrs
mxinden Jun 1, 2022
449462b
webrtc/: Document open question of key derivation for TLS cert
mxinden Jun 1, 2022
3e9fb70
webrtc/: Determine UDP port for browser-to-browser
mxinden Jun 3, 2022
81249f3
webrtc/: Add open question on udp vs tcp
mxinden Jun 22, 2022
ee09ed4
webrtc/README: Update with reuse of certificates
mxinden Jun 27, 2022
d451652
webrtc/: Answer question no double muxing
mxinden Jun 27, 2022
b485340
webrtc/: Reword connecting to instantiating
mxinden Jun 27, 2022
b654f11
webrtc/: Document generating valid SDP packet
mxinden Jun 27, 2022
9a90f0d
webrtc/: Restructure sections with Open Questions section each
mxinden Jul 1, 2022
baccb1d
webrtc/: Document DCUtR in browser-to-browser use-case
mxinden Jul 1, 2022
83e7aa0
webrtc/: Document client fingerprint in STUN username
mxinden Jul 1, 2022
766bb62
webrtc/: Detail Multiplexing and Security in separate section
mxinden Jul 1, 2022
525bc9e
webrtc/: Document UDP port multiplexing and ICE lite
mxinden Jul 1, 2022
3e9e6df
webrtc/: Document potential attack vectors using STUN
mxinden Jul 1, 2022
a29cb45
webrtc/: Write out additional Noise handshake
mxinden Jul 1, 2022
827def2
webrtc/: Delete outdated comment on browsers
mxinden Jul 1, 2022
e6c23e1
webrtc/: Document Firefox not connecting on localhost
mxinden Jul 6, 2022
5f7ea61
webrtc/: Document random string in STUN username and password
mxinden Jul 12, 2022
f5eb1b7
webrtc/: Document potential amplification defense through large clien…
mxinden Jul 12, 2022
a8a42b5
webrtc/: Document certhash being a multibase encoded multihash
mxinden Jul 12, 2022
c8e725a
webrtc/: Document hash function match on WebRTC and Noise
mxinden Jul 12, 2022
7e601e7
webrtc/: Track open question on whether server should initiate Noise
mxinden Jul 12, 2022
9e8ec87
webrtc/readme/faq: Write out the need for handshake over plain sigs
mxinden Jul 21, 2022
cceed49
webrtc/: Fix typo fingerprint -> signature
mxinden Jul 21, 2022
c5522c4
webrtc/: Document open question on Noise optimization
mxinden Jul 27, 2022
c89a72a
webrtc/: Reword Motivation section
mxinden Aug 2, 2022
bc76a06
webrtc/: Document UDP port per RTCPeerConnection
mxinden Aug 2, 2022
a0ae9b0
webrtc/: Extend on UDP muxing support across implementations
mxinden Aug 2, 2022
774cd52
webrtc/: Document SDP munging
mxinden Aug 2, 2022
ae1020b
webrtc/: Document Noise Prologue mechanism
mxinden Aug 2, 2022
4b8e890
webrtc/: Require signature tag and sorted fingerprints
mxinden Aug 4, 2022
285574d
webrtc/: Add message framing to support half-close and reset of stream
mxinden Aug 18, 2022
7009f94
webrtc/: Specify sha256 and base64url
mxinden Aug 19, 2022
373bafe
webrtc/: Reword protobuf comment from local endpoint to sender
mxinden Aug 22, 2022
93df7e3
webrtc/: Adapt enum variants to QUIC RFC
mxinden Sep 5, 2022
027b539
webrtc/: Link QUIC RFC as reference
mxinden Sep 5, 2022
865f4f2
webrtc/: Redefine RESET semantics
mxinden Sep 5, 2022
a60234c
webrtc/: Rephrase missing mechanism in browser webrtc api
mxinden Sep 5, 2022
48f5fe7
webrtc/: Add note on stream ordering
mxinden Sep 8, 2022
7f40491
Apply suggestions from code review
mxinden Sep 10, 2022
31ac65d
webrtc/: Require RESET after STOP_SENDING
mxinden Sep 10, 2022
85364f4
webrtc/: Rename RESET to RESET_STREAM
mxinden Sep 10, 2022
9ce0d45
webrtc/: Allow overriding ordering on a data channel
mxinden Sep 10, 2022
2570b24
Merge branch 'webrtc' of github.com:mxinden/specs into webrtc-msg-fra…
mxinden Sep 10, 2022
7a8ebc0
webrtc/: Use message framing for Noise handshake already
mxinden Sep 11, 2022
f0acbb5
Update webrtc/README.md
mxinden Sep 13, 2022
6df6cf3
Merge pull request #1 from mxinden/webrtc-msg-framing
mxinden Sep 13, 2022
c19ba8a
webrtc/README.md: Fix typo
mxinden Sep 16, 2022
65a894a
webrtc/: Don't require STREAM_RESET in response to STOP_SENDING
mxinden Sep 22, 2022
6fb2750
Add initial test vector for noise prologue
thomaseizinger Sep 23, 2022
73516b1
Add note about encoding
thomaseizinger Sep 23, 2022
8208f02
webrtc/: Document option for not using trickle ICE
mxinden Sep 25, 2022
6c7f18e
webrtc/: Mention icegatheringstatechange event on the browser
mxinden Sep 25, 2022
666c9f4
webrtc/: Use id 0 and negotiated true for Noise channel
mxinden Sep 25, 2022
ae5b0d8
webrtc/: Document allowing streams before Noise finished
mxinden Sep 25, 2022
7ce6213
webrtc/: Use IP + port + ufrag for multiplexing
mxinden Sep 25, 2022
a2d1547
webrtc/: Remove open question on SDP munging
mxinden Sep 25, 2022
ded63c5
webrtc/: Reword certificate verification section
mxinden Sep 28, 2022
54f8264
webrtc/: Recommend against reusing the TLS certificate
mxinden Sep 28, 2022
67e12da
webrtc/: Document B listening via UDP socket
mxinden Sep 28, 2022
4a52edc
webrtc/: Add uvarint link
mxinden Sep 28, 2022
7380483
webrtc/: Remove mention of saved round trip
mxinden Sep 28, 2022
c063a81
webrtc/: Move fingerprint extraction to statement instead of question
mxinden Sep 28, 2022
65590f9
webrtc/: Remove obsolete question on preceeding SDP packet
mxinden Sep 28, 2022
8dc6465
webrtc/: Remove open question on handshake security
mxinden Sep 28, 2022
daecb5b
README.md: Link to WebRTC specification
mxinden Sep 28, 2022
6267324
Merge branch master into webrtc
mxinden Sep 28, 2022
590c3db
connections/hole-punching: Link to WebRTC specification
mxinden Sep 28, 2022
a207aa5
webrtc/: Document open questions on data channel IDs
mxinden Sep 30, 2022
ed5c641
webrtc/: Document head-of-line blocking
mxinden Oct 5, 2022
42e7a20
webrtc/: Recommend concrete maximum message size
mxinden Oct 5, 2022
3315b5c
webrtc/: Document stream negotiation and ids
mxinden Oct 5, 2022
2dddfdc
webrtc/: Remove open questions on data channel negotiation and ids
mxinden Oct 5, 2022
0deaa30
webrtc/: Make certificate reuse a SHOULD NOT
mxinden Oct 5, 2022
7ac21aa
webrtc/: Fix typo
mxinden Oct 5, 2022
8803682
webrtc/: Draft the browser-to-browser section
mxinden Oct 5, 2022
b5466fd
webrtc/: Have B start Noise handshake
mxinden Oct 12, 2022
4931f87
webrtc/: Fix fingerprint hash algorithm to sha-256
mxinden Oct 12, 2022
d5d164b
webrtc/: Document replacement of webrtc direct and star
mxinden Oct 12, 2022
6775d10
webrtc/: Document setting ondatachannel callback before noise
mxinden Oct 12, 2022
730dca0
webrtc/: Order Protologue fingerprints by role not by sorting
mxinden Oct 12, 2022
faf641d
webrtc/: Use RTCDataChannel `negotiated: false`
mxinden Oct 12, 2022
e2df94c
webrtc/: Link to RFC and not Chromium codebase for stream reuse
mxinden Oct 12, 2022
b268693
webrtc/: Rephrase stream reuse and mention concurrent limit
mxinden Oct 13, 2022
3aebc68
webrtc/: Drop hope for not having to use STUN
mxinden Oct 13, 2022
50b4e12
webrtc/: Rephrase requirements as FAQs
mxinden Oct 13, 2022
c8df617
webrtc/: Document setting username and password on local and remote SDP
mxinden Oct 13, 2022
4de8f96
webrtc/: Document amplification and DOS attack defense
mxinden Oct 13, 2022
4dcf801
webrtc/: Document reason for B starting noise handshake
mxinden Oct 13, 2022
16e38fb
webrtc/: Remove derivation of TLS certificate
mxinden Oct 13, 2022
f635466
webrtc: Document MUST for UDP and MAY for TCP
mxinden Oct 13, 2022
5c9b600
Merge branch 'master' of https://github.com/libp2p/specs into webrtc
mxinden Oct 13, 2022
961ada2
Merge remote-tracking branch 'mxinden/webrtc' into prologue-test-vectors
thomaseizinger Oct 14, 2022
75c3b5c
Update test vector to remove sorting requirement
thomaseizinger Oct 14, 2022
9abf638
webrtc/: Document RTCDataChannel label to be an empty string
mxinden Oct 14, 2022
1cb4093
webrtc/: Track RTCDatachannel label in TOC
mxinden Oct 14, 2022
a46919c
webrtc/: Remove browser-to-browser use-case
mxinden Oct 14, 2022
3058fb9
webrtc/: Update "Previous, ongoing and related work" section
mxinden Oct 14, 2022
a382f18
webrtc/: Add revision
mxinden Oct 14, 2022
44fd082
webrtc/: Fix interest group links
mxinden Oct 14, 2022
22fc557
Merge pull request #2 from thomaseizinger/prologue-test-vectors
mxinden Oct 14, 2022
1ddc317
webrtc/: Document role on test vectors
mxinden Oct 20, 2022
1e3ca59
webrtc/: Fix typo generating an offer for B
mxinden Oct 20, 2022
b1f629a
webrtc/: Fix more offer answer confusions
mxinden Oct 20, 2022
070ebea
webrtc/: Reword server generating SDP offer
mxinden Oct 20, 2022
072c317
Update webrtc/README.md
mxinden Oct 20, 2022
b8dc6fd
webrtc/: Mark server's peer ID as optional
mxinden Oct 20, 2022
a62fdd2
Update webrtc/README.md
mxinden Oct 20, 2022
118a4dc
Merge remote-tracking branch 'libp2p/master' into webrtc
mxinden Oct 22, 2022
60ac97a
webrtc/: Mention WebTransport specification
mxinden Oct 22, 2022
6846d34
webrtc/: s/listen/bind for UDP socket
mxinden Oct 22, 2022
c369f2b
Update webrtc/README.md
mxinden Oct 22, 2022
0c4e836
Update webrtc/README.md
mxinden Oct 22, 2022
dd9756b
webrtc/: Fix maximum packet size calculation
mxinden Oct 22, 2022
249ebd2
webrtc/: Mention head-of-line-blocking on packet size recommendation
mxinden Oct 22, 2022
be5cfeb
webrtc/: Emphasize prologue prefix representation in bytes
mxinden Oct 22, 2022
602f492
webrtc/: Require A to use same hash alg as B and REQUIRE sha-256 support
mxinden Oct 22, 2022
1c7956c
webrtc/: Prefix random ufrag string for future upgrades
mxinden Oct 22, 2022
b5ac74b
webrtc/README.md: Refer to plural RTCDataChannel
mxinden Oct 26, 2022
b6e7eb1
webrtc/README.md: Use valid ufrag prefix
mxinden Nov 2, 2022
2d0478c
webrtc/: Add max-message-size SDP attribute
mxinden Nov 2, 2022
4dc788c
webrtc/: Fix typo
mxinden Nov 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
323 changes: 323 additions & 0 deletions webrtc/README.md
@@ -0,0 +1,323 @@
# WebRTC

| Lifecycle Stage | Maturity | Status | Latest Revision |
|-----------------|---------------|--------|-----------------|
| 1A | Working Draft | Active | |

Authors: [@mxinden]

Interest Group: [@marten-seemann]

<!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc -->
**Table of Contents**

- [WebRTC](#webrtc)
- [Motivation](#motivation)
- [Requirements](#requirements)
- [Addressing](#addressing)
- [Connection Establishment](#connection-establishment)
- [Browser to public Server](#browser-to-public-server)
- [Open Questions](#open-questions)
- [Browser to Browser](#browser-to-browser)
- [Open Questions](#open-questions-1)
- [Connection Security](#connection-security)
- [Open Questions](#open-questions-2)
- [Multiplexing](#multiplexing)
- [General Open Questions](#general-open-questions)
- [Previous, ongoing and related work](#previous-ongoing-and-related-work)
- [FAQ](#faq)

<!-- markdown-toc end -->


## Motivation

1. **No need for valid TLS certificates.** Enable browsers to connect to public
server nodes without those server nodes providing a TLS certificate within
the browsers trustchain. Note that we can not do this today with our
Websocket transport.

2. **Hole punching in the browser**: Enable two browsers or a browser and a
non-public server node to connect.

## Requirements

- Loading a remote nodes certificate into ones browser trust-store is not an
mxinden marked this conversation as resolved.
Show resolved Hide resolved
option, i.e. doesn't scale.

- No dependency on central STUN and/or TURN servers.

## Addressing

WebRTC multiaddresses are composed of an IP and UDP address component, followed
by `/webrtc` and a multihash of the certificate that the node uses.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In multiformats/multiaddr#130 (comment) @tomaka suggests to use /webrtc-direct instead of /webrtc. I think this is a better place for this discussion to take place.

Why /webrtc-direct instead of /webrtc? Because we know that we will add alternative WebRTC protocols in the future. I like the fact that /webrtc-direct conveys the idea that this is one opinionated way of connecting through WebRTC, rather than the WebRTC protocol.

Agreed that we might add other flavors (e.g. always double encrypting via nested Noise), though I would expect that the flavor we are adding here (this specification) will be the most used one, thus deserving the short name.

To the best of my knowledge, we don't need a separate protocol name for the browser-to-browser use-case. I.e. we can use the same /webrtc protocol name. Though, given that we haven't yet designed it, I might be missing something.

What do folks think? @tomaka would you expect as well that this flavor will become the most prominent one and thus deserves the shorter name?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more specific name is a good thing, given that we already have webrtc-star and webrtc-direct transports.

These use the multiaddr formats /ip4/$ADDR/tcp/$PORT/wss/p2p-webrtc-star/p2p/QmFoo and /ip4/$ADDR/tcp/$PORT/http/p2p-webrtc-direct/QmFoo respectively.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not going to push for this, i.e. I don't intend to change the protocol name. In case folks do feel strongly about this, please speak up.


Examples:
- `/ip4/1.2.3.4/udp/1234/webrtc/certhash/<hash>/p2p/<peer-id>`
mxinden marked this conversation as resolved.
Show resolved Hide resolved
mxinden marked this conversation as resolved.
Show resolved Hide resolved
- `/ip6/fe80::1ff:fe23:4567:890a/udp/1234/webrtc/certhash/<hash>/p2p/<peer-id>`

The TLS certificate fingerprint in `/certhash` is a
[multibase](https://github.com/multiformats/multibase) encoded
[multihash](https://github.com/multiformats/multihash).

## Connection Establishment

### Browser to public Server

Scenario: Browser _A_ wants to connect to server node _B_ where _B_ is publicly
reachable but _B_ does not have a TLS certificate trusted by _A_.

As a preparation browser _A_ [generates a
certificate](https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-generatecertificate)
and [gets the certificate's
fingerprint](https://www.w3.org/TR/webrtc/#dom-rtccertificate-getfingerprints).

1. Browser _A_ discovers server node _B_'s multiaddr, containing _B_'s IP, UDP
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically, we’ll discover multiple WebRTC multiaddrs. IPv4 and IPv6 at the very least. We should specify how this is handled. I assume we’d combine them into the same SDP.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume we’d combine them into the same SDP.

That's not the case right now (not in Rust implementation at least).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I can tell there is no benefit for combining multiple WebRTC multiaddrs into a single connection attempt in the browser-to-server use-case. @marten-seemann did you had one in mind for the browser-to-server use-case?

Agreed that we should combine them for the browser-to-browser use-case, though I would like to delay that discussion to the second iteration of this specification.

port, TLS certificate fingerprint and libp2p peer ID (e.g.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean we always require a PeerId for dialing a WebRTC address? rust-libp2p in general also allows dialing without a /p2p postfix. For this spec though, we fail to dial in case the /p2p part is not present. Is this intended from this wording?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would this work with the noise handshake if we do not know the remote's peer ID?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch @thomaseizinger. Addressed in b8dc6fd.

How would this work with the noise handshake if we do not know the remote's peer ID?

@ckousik we are using the Noise XX handshake pattern. With this pattern the two peers exchange their peer ID within the Noise exchange.

This does have security implications. See #458 for more details.

`/ip6/2001:db8::/udp/1234/webrtc/certhash/<hash>/p2p/<peer-id>`),
through some external mechanism.

2. _A_ instantiates a `RTCPeerConnection`, passing its local certificate as a
parameter. See
[`RTCPeerConnection()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection).

3. _A_ constructs _B_'s SDP offer locally based on _B_'s multiaddr and sets it
mxinden marked this conversation as resolved.
Show resolved Hide resolved
via
[`RTCPeerConnection.setRemoteDescription()`](https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/setRemoteDescription).

4. _A_ establishes the connection to _B_. _A_ generates a random string and uses
that string as the username (_ufrag_ or _username fragment_) and password in
the initial STUN message from _A_ to _B_. The random string can be used by
_B_ to identify the connection, i.e. demultiplex incoming UDP datagrams per
incoming connection. _B_ uses the same random string for the username and
password of the STUN message from _B_ to _A_.

5. _B_ does not know the TLS fingerprint of _A_. _B_ upgrades the incoming
connection from _A_ as an _insecure_ connection, learning _A_'s TLS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t understand this sentence. What does upgrading as an insecure connection mean, as opposed to upgrading as a secure connection?

I think we should avoid the term „upgrading“ altogether.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ded63c5 rephrases the section. @marten-seemann let me know what you think.

fingerprint through the WebRTC DTLS handshake. At this point the DTLS
handshake provides confidentiality and integrity but not authenticity.

mxinden marked this conversation as resolved.
Show resolved Hide resolved
6. See [Connection Security](#connection-security).

7. See [Multiplexing](#multiplexing).

#### Open Questions

- Is the fact that the server accepts STUN messages from the client prone to
attacks?

- Can an attacker launch an **amplification attack** with the STUN endpoint
of the server?
mxinden marked this conversation as resolved.
Show resolved Hide resolved

The QUIC protocol defends against amplification attacks by requiring:

> an endpoint MUST limit the amount of data it sends to the unvalidated
> address to three times the amount of data received from that address.

https://datatracker.ietf.org/doc/html/rfc9000#section-8

For WebRTC in libp2p one could require the client (_A_) to add additional
bytes to its STUN message, e.g. in the STUN username and password, thus
making an amplification attack less attractive.

- Can a client run a **DOS attack** by sending many STUN messages with
different ufrags using different UDP source ports, forcing the server to
allocate a new peer connection for each? Would rate limiting suffice to
defend against this attack?
mxinden marked this conversation as resolved.
Show resolved Hide resolved

See also:
- https://datatracker.ietf.org/doc/html/rfc5389#section-16.2.1
- https://datatracker.ietf.org/doc/html/rfc5389#section-16.1.2

- Do the major WebRTC server implementations support using the same UDP port for
mxinden marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have been resolved. I think this should be moved as a statement to the section above (“major WebRTC implementations support demultiplexing…”), maybe with a short explanation how the demultiplexing is achieved.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed with 67e12da including a short explainer on how to do multiplexing on the UDP socket. Happy for additional wording suggestions.

multiple WebRTC connections, thus requiring multiplexing multiple WebRTC
connections on the same UDP port? In particular this came up for NodeJS.

This is related to [ICE Lite](https://www.rfc-editor.org/rfc/rfc5245), having
a host only advertise a single address, namely the host address, which is
assumed to be public.

- Do the major (Go / Rust / ...) WebRTC implementations allow us to accept a
mxinden marked this conversation as resolved.
Show resolved Hide resolved
WebRTC connection from a remote node without previously receiving an SDP
packet from such host?

- Can _Browser_ generate a _valid_ SDP packet for the remote node based on the
mxinden marked this conversation as resolved.
Show resolved Hide resolved
remote's Multiaddr, where that Multiaddr contains the IP, UDP port and TLS
certificate fingerprint (e.g.
`/ip6/2001:db8::/udp/1234/webrtc/certhash/<hash>/p2p/<peer-id>`)? _Valid_ in
the sense that this generated SDP packet can then be used to establish a
WebRTC connection to the remote.

mxinden marked this conversation as resolved.
Show resolved Hide resolved
mxinden marked this conversation as resolved.
Show resolved Hide resolved
Yes.

### Browser to Browser

Scenario: Browser _A_ wants to connect to Browser node _B_ with the help of
server node _R_.

- Replace STUN with libp2p's identify and AutoNAT
- https://github.com/libp2p/specs/tree/master/identify
- https://github.com/libp2p/specs/blob/master/autonat/README.md
- Replace TURN with libp2p's Circuit Relay v2
- https://github.com/libp2p/specs/blob/master/relay/circuit-v2.md
- Use DCUtR over Circuit Relay v2 to transmit SDP information
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DCUtR seems like a poor fit for this use case (I think I’ve mentioned that before). All we need to do is transfer a list of multiaddrs in both directions, there’s no need for the two-step protocol (SYNC, CONNECT) that DCUtR uses.

1. Transform ICE candidates in SDP to multiaddresses.
2. Transmit the set of multiaddresses to the remote via DCUtR.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using DCUtR seems to prevent trickling. This really should be its own protocol.

3. Transform the set of multiaddresses back to the remotes SDP.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we get rid of the two transformation steps by transmitting the SDP directly.

4. https://github.com/libp2p/specs/blob/master/relay/DCUtR.md

#### Open Questions

- Can _Browser_ know upfront its UDP port which it is listening for incoming
connections on? Does the browser reuse the UDP port across many WebRTC
mxinden marked this conversation as resolved.
Show resolved Hide resolved
connections? If that is the case one could connect to any public node, with
the remote telling the local node what port it is perceived on.

- Can _Browser_ control the lifecycle of its local TLS certificate, i.e. can
mxinden marked this conversation as resolved.
Show resolved Hide resolved
_Browser_ use the same TLS certificate for multiple WebRTC connections?

Yes. For the lifetime of the page, one can generate a certificate once and
reuse it across connections. See also
https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#using_certificates

- Can two _Browsers_ exchange their SDP packets via a third server node using
mxinden marked this conversation as resolved.
Show resolved Hide resolved
Circuit Relay v2 and DCUtR? Instead of exchanging the original SDP packets,
could they exchange their multiaddr and construct the remote's SDP packet
mxinden marked this conversation as resolved.
Show resolved Hide resolved
based on it?

## Connection Security

While WebRTC offers confidentiality and integrity via TLS, one still needs to
authenticate the remote peer by its libp2p identity.

After [Connection Establishment](#connection-establishment):

1. _A_ opens a WebRTC datachannel and starts a Noise handshake using _A_'s and
_B_'s libp2p identity. See
[noise-libp2p](https://github.com/libp2p/specs/tree/master/noise).

2. _A_ and _B_ write their TLS certificate fingerprint on the negotiated Noise
channel as multibase encoded multihashes (see [#addressing]).
mxinden marked this conversation as resolved.
Show resolved Hide resolved

3. _A_ and _B_ read the other sides TLS certificate fingerprint on the
negotiated Noise channel and compare it to the ones verified during the DTLS
handshake.

Note: WebRTC supports different hash functions to hash the TLS certificate
(see https://datatracker.ietf.org/doc/html/rfc8122#section-5). The hash
function used in WebRTC, the hash function used for the hash exchanged in the
additional Noise handshake and the hash function used in the multiaddr
`/certhash` component MUST be the same. On mismatch the final Noise handshake
MUST fail.

### Open Questions

- Can a _Browser_ access the fingerprint of its TLS certificate?
mxinden marked this conversation as resolved.
Show resolved Hide resolved

Chrome allows you to access the fingerprint of any locally-created certificate
directly via `RTCCertificate#getFingerprints`. Firefox does not allow you to
do so. Browser compatibility can be found
[here](https://developer.mozilla.org/en-US/docs/Web/API/RTCCertificate). In
practice, this is not an issue since the fingerprint is embedded in the local
SDP string.

- Is the above proposed additional handshake secure? See also alternative
proposed Handshake for
[WebTransport](https://github.com/libp2p/specs/pull/404).

- Would it be more efficient for _B_ to initiate the Noise handshake? In other
words, who is able to write on an established WebRTC connection first? _A_ or
_B_?
mxinden marked this conversation as resolved.
Show resolved Hide resolved

- Instead of exchanging the TLS fingerprints once the Noise handshake finished,
could one instead attach the fingerprints to the Noise handshake messages as
additional payloads? That would reduce the overall connection establishment
latency by one round trip. Would this schema be secure using the Noise XX
handshake pattern?
mxinden marked this conversation as resolved.
Show resolved Hide resolved

- On the server side, can one derive the TLS certificate in a deterministic way
based on a node's libp2p private key? Benefit would be that a node only needs
to persist the libp2p private key and not the TLS key material while still
maintaining a fixed TLS certificate fingerprint.
mxinden marked this conversation as resolved.
Show resolved Hide resolved

## Multiplexing

After [Connection Security](#connection-security):

1. On success of the authentication handshake _X_, the used datachannel is
mxinden marked this conversation as resolved.
Show resolved Hide resolved
closed and the plain WebRTC connection is used with its multiplexing
capabilities via datachannels.

### Open Questions

- Can we use WebRTC’s data channels in _Browser_ to multiplex a single
mxinden marked this conversation as resolved.
Show resolved Hide resolved
connection, or do we need to run an additional multiplexer (e.g. yamux) on top
of a WebRTC connection and WebRTC datachannel? In other words, does WebRTC
provide all functionality of a libp2p muxer like Yamux (e.g. flow control)?

Yes, with WebRTC's datachannels running on top of SCTP, there is no need for
additional multiplexing.

## General Open Questions

- Should libp2p's WebRTC stack limit itself to using UDP only, or support WebRTC
on top of both UDP and TCP?

- Is the fact that Firefox does not allow a WebRTC to `localhost` an issue? See
https://bugzilla.mozilla.org/show_bug.cgi?id=831926.

## Previous, ongoing and related work

- Proof of concept for the server side in rust-libp2p:
https://github.com/libp2p/rust-libp2p/pull/2622
mxinden marked this conversation as resolved.
Show resolved Hide resolved

- Proof of concept for the server side (native) and the client side (Rust in
WASM): https://github.com/wngr/libp2p-webrtc

- WebRTC using STUN and TURN: https://github.com/libp2p/js-libp2p-webrtc-star

# FAQ

- _Why exchange the TLS certificate fingerprint in the multiaddr? Why not
base it on the libp2p public key?_

Browsers do not allow loading a custom certificate. One can only generate a
certificate via
[rtcpeerconnection-generatecertificate](https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-generatecertificate).

- _Why not embed the peer ID in the TLS certificate, thus rendering the
additional "peer certificate" exchange obsolete?_

Browsers do not allow editing the properties of the TLS certificate.

- _How about distributing the multiaddr in a signed peer record, thus rendering
the additional "peer certificate" exchange obsolete?_

Signed peer records are not yet rolled out across the many libp2p protocols.
Making the libp2p WebRTC protocol dependent on the former is not deemed worth
it at this point in time. Later versions of the libp2p WebRTC protocol might
adopt this optimization.

Note, one can role out a new version of the libp2p WebRTC protocol through a
new multiaddr protocol, e.g. `/webrtc-2`.

- _Why exchange fingerprints in an additional authentication handshake on top of
an established WebRTC connection? Why not only exchange signatures of ones TLS
fingerprints signed with ones libp2p private key on the plain WebRTC
connection?_

Once _A_ and _B_ established a WebRTC connection, _A_ sends
`signature_libp2p_a(fingerprint_a)` to _B_ and vice versa. While this has the
benefit of only requring two messages, thus one round trip, it is prone to a
key compromise and replay attack. Say that _E_ is able to attain
`signature_libp2p_a(fingerprint_a)` and somehow compromise _A_'s TLS private
key, _E_ can now impersonate _A_ without knowing _A_'s libp2p private key.

If one requires the signatures to contain both fingerprints, e.g.
`signature_libp2p_a(fingerprint_a, fingerprint_b)`, the above attack still
works, just that _E_ can only impersonate _A_ when talking to _B_.

Adding a cryptographic identifier of the unique connection (i.e. session) to
the signature (`signature_libp2p_a(fingerprint_a, fingerprint_b,
connection_identifier)`) would protect against this attack. To the best of our
knowledge the browser does not give us access to such identifier.
mxinden marked this conversation as resolved.
Show resolved Hide resolved