diff --git a/connections/README.md b/connections/README.md index 1d51b498f..22338f622 100644 --- a/connections/README.md +++ b/connections/README.md @@ -2,7 +2,7 @@ | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------|--------|-----------------| -| 1A | Working Draft | Active | r0, 2019-06-20 | +| 1A | Working Draft | Active | r1, 2022-12-07 | Authors: [@yusefnapora] @@ -234,6 +234,11 @@ Note: In the case where both peers initially act as initiators, e.g. during NAT hole punching, tie-breaking is done via the [multistream-select simultaneous open protocol extension][simopen]. +### Inlining Muxer Negotiation + +If both peers support it, it's possible to shortcut the muxer selection by moving +it into the security handshake. Details are specified in [inlined-muxer-negotiation]. + ## Opening New Streams Over a Connection @@ -409,3 +414,4 @@ updated to incorporate the changes. [simopen]: ./simopen.md [resource-manager-issue]: https://github.com/libp2p/go-libp2p/issues/635 [hole-punching]: ./hole-punching.md +[inlined-muxer-selection]: ./inlined-muxer-negotiation.md diff --git a/connections/inlined-muxer-negotiation.md b/connections/inlined-muxer-negotiation.md new file mode 100644 index 000000000..a437dfce9 --- /dev/null +++ b/connections/inlined-muxer-negotiation.md @@ -0,0 +1,128 @@ +# Stream multiplexer negotiation in security handshake + + +| Lifecycle Stage | Maturity | Status | Latest Revision | +|-----------------|---------------|--------|-----------------| +| 1A | Working Draft | Active | r1, 2022-12-07 | + +Authors: [@julian88110], [@marten-seemann] + +Interest Group: [@marcopolo], [@mxinden] + +[@marten-seemann]: https://github.com/marten-seemann +[@marcopolo]: https://github.com/marcopolo +[@mxinden]: https://github.com/mxinden +[@julian88110]: https://github.com/julian88110 + +See the [lifecycle document][lifecycle-spec] for context about maturity level +and spec status. + +[lifecycle-spec]: https://github.com/libp2p/specs/blob/master/00-framework-01-spec-lifecycle.md + +## Table of Contents + +- [Overview](#overview) +- [Design](#design) + - [Multiplexer Negotiation over TLS](#multiplexer-negotiation-over-tls) + - [Multiplexer Negotiation over Noise](#multiplexer-negotiation-over-noise) +- [Privacy](#privacy) +- [Alternative options considered](#alternative-options-considered) + +## Overview + +Transports that don't support native stream multiplexing (e.g. TCP, WebSocket) negotiate +a stream multiplexer after completion of the cryptographic handshake, as described in [connections]. +Negotiating the stream multiplexer takes one network roundtrip. +This document defines a backwards-compatible optimization, which allows running the +multiplexer negotiation during the cryptographic handshake, thereby reducing the latency of +connection establishment by one roundtrip. + + +## Design + +### Multiplexer Negotiation over TLS + +When using TLS, the [ALPN] extension is used to negotiate the multiplexer. + +The ALPN TLS extension allows the client to send a list of supported application +protocols as part of the TLS `ClientHello` message. The server chooses +a protocol and sends the selected protocol as part of the TLS +`ServerHello` message. + +For the purpose of multiplexer negotiation, the protocol IDs of the stream +multiplexers are sent, followed by the `"libp2p"` protocol code. The multiplexer list is ordered by +the client's preference, with the most preferred multiplexer at the beginning. +The server SHOULD respect the client's preference and pick the first protocol +from the list that it supports. + +Example for a node supporting both yamux and mplex, with a preference for yamux: +```json +[ "/yamux/1.0.0", "/mplex/6.7.0", "libp2p" ] +``` + +The `"libp2p"` protocol code MUST always be the last item in the multiplexer list. +According to [TLS], nodes that don't implement the optimization described in +this document use `"libp2p"` for their ALPN. If `"libp2p"` is the result of the +ALPN process, nodes MUST use protocol negotiation of the stream multiplexer +as described in [connections]. + +### Multiplexer Negotiation over Noise + +The libp2p Noise Specification allows Noise handshake messages to carry +early data. [Noise-Early-Data] is carried in the second and third message of +the XX handshake pattern as illustrated in the following message sequence chart. +The second message carries early data in the form of a list of multiplexers +supported by the responder. The initiator sends its supported multiplexer list +in the third message of the handshake process, ordered by its preference. It +MAY choose a single multiplexer from the responder's list and only send that +value. + +The multiplexer to use is determined by picking the first item from the +initiator's list that both parties support. + +Example: Noise handshake between two clients that both support mplex and yamux. The +client prefers yamux, whereas the server prefers mplex. + +``` +XX: +-> e +<- e, ee, s, es, [ "/mplex/6.7.0", "/yamux/1.0.0" ] +-> s, se, [ "/yamux/1.0.0", "/mplex/6.7.0" ] +``` + +The result of this negotiation is `"/mplex/6.7.0"`. + +If there is no overlap between the multiplexers support by client and server, +the handshake MUST fail. + +The format of the early data is specified in [Noise-handshake-payload]. + + +## Privacy + +The list of multiplexers carried in the TLS ALPN extension field is part of the +unencrypted ClientHello message. Therefore, using this optimization +exposes the list of supported multiplexers to an on-path observer. This leak can +be considered insignificant, since a libp2p node reveals its list of supported +multiplexers to any node that connects to it. + +However, the NoiseExtensions in the Noise handshake are sent after the peers have +established a shared key, so an on-path observer won't be able to obtain the +list of multiplexers. + + +## Alternative options considered + +Instead of ALPN for multiplexer selection to reduce RTT, other options such as +TLS extension and X.509 extension were considered. The pros and cons are explored +and the discussion details can be found at [#454]. + + +[TLS]: https://github.com/libp2p/specs/blob/master/tls/tls.md +[connections]: https://github.com/libp2p/specs/tree/master/connections +[ALPN]: https://datatracker.ietf.org/doc/html/rfc7301 +[Noise-Early-Data]: https://github.com/libp2p/specs/tree/master/noise#libp2p-data-in-handshake-messages +[ECH]: https://datatracker.ietf.org/doc/draft-ietf-tls-esni/ +[#454]: https://github.com/libp2p/specs/issues/454 +[Noise-handshake-payload]: https://github.com/libp2p/specs/tree/master/noise#the-libp2p-handshake-payload + diff --git a/noise/README.md b/noise/README.md index 7648b06d1..714c80a34 100644 --- a/noise/README.md +++ b/noise/README.md @@ -5,7 +5,7 @@ | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|----------------|--------|-----------------| -| 3A | Recommendation | Active | r4, 2022-09-22 | +| 3A | Recommendation | Active | r5, 2022-12-07 | Authors: [@yusefnapora] @@ -220,6 +220,7 @@ syntax = "proto2"; message NoiseExtensions { repeated bytes webtransport_certhashes = 1; + repeated string stream_muxers = 2; } message NoiseHandshakePayload {