From 01b4b079b4b4e0c7245c715f79918d72da22cef0 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 9 Sep 2019 08:58:48 -0400 Subject: [PATCH 1/4] clarify Noise Pipes as optional & possibly YAGNI --- noise/README.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/noise/README.md b/noise/README.md index d74a1570e..2e2b62030 100644 --- a/noise/README.md +++ b/noise/README.md @@ -93,9 +93,17 @@ traffic. The [Noise Handshake section](#the-noise-handshake) describes the libp2p-specific data is exchanged during the handshake](#libp2p-data-in-handshake-messages). -During the handshake, the static -DH key used for Noise is authenticated using the libp2p identity keypair, as -described in the [Static Key Authentication section](#static-key-authentication). +By default, noise-libp2p uses the [`XX` handshake pattern](#xx), which provides +strong privacy and security guarantees and requires 1.5 round trip message +exchanges to be sound. Implementations may optionally support a compound +protocol called "Noise Pipes." Noise Pipes allows peers to attempt the more +efficient [`IK` handshake pattern](#ik) using a cached static key, falling back +to the `XX` pattern if the `IK` attempt fails. For details, see [Optimistic +0-RTT With Noise Pipes](#optimistic-0-rtt-with-noise-pipes). + +During the handshake, the static DH key used for Noise is authenticated using +the libp2p identity keypair, as described in the [Static Key Authentication +section](#static-key-authentication). Following a successful handshake, peers use the resulting encryption keys to send ciphertexts back and forth. The format for transport messages and the wire @@ -275,7 +283,9 @@ handshake pattern. The [IK handshake pattern](#ik) is used in the context of [Optimistic 0-RTT with Noise Pipes](#optimistic-0-rtt-with-noise-pipes) and is described in that section along with the [`XXfallback`](#xxfallback) variation on the `XX` -pattern. +pattern. Support for `IK` and `XXfallback` is optional, and they are only +supported in the context of the Noise Pipes pattern. Implementations that do not +support Noise Pipes should not support the `IK` handshake. #### XX @@ -335,6 +345,16 @@ implementations that do support it SHOULD offer a single configuration option to enable Noise Pipes, rather than separate options for enabling `IK` and `XXfallback`. +Although Noise Pipes can be more efficient than the default `XX` pattern, it's +worth noting that in many real-world use cases the difference is not as large as +it would appear at a glance. While `XX` requires 1.5 round trips, the final +handshake message (sent by the initiator) can be immediately followed by a +transport message, both of which will almost certainly fit in the same network +packet or datagram. In cases where the initiator of the handshake is also the +party expected to send the first transport message (as in the common request / +reply scenario), the cost of the final handshake message is effectively +eliminated. + #### IK From 18d1b705c1a63a8f0b121dba1ba964e458bf8a54 Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 9 Sep 2019 09:18:08 -0400 Subject: [PATCH 2/4] remove padding in payloads & rename handshake payload section --- noise/README.md | 72 +++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/noise/README.md b/noise/README.md index 2e2b62030..a86435144 100644 --- a/noise/README.md +++ b/noise/README.md @@ -33,7 +33,7 @@ and spec status. - [The Noise Handshake](#the-noise-handshake) - [Static Key Authentication](#static-key-authentication) - [libp2p Data in Handshake Messages](#libp2p-data-in-handshake-messages) - - [The libp2p Signed Handshake Payload](#the-libp2p-signed-handshake-payload) + - [The libp2p Handshake Payload](#the-libp2p-handshake-payload) - [Supported Handshake Patterns](#supported-handshake-patterns) - [XX](#xx) - [Optimistic 0-RTT with Noise Pipes](#optimistic-0-rtt-with-noise-pipes) @@ -180,9 +180,9 @@ exposure. To authenticate the static Noise key used in a handshake, noise-libp2p includes a signature of the static Noise public key in a [handshake -payload](#the-libp2p-signed-handshake-payload). This signature is produced with -the private libp2p identity key, which proves that the sender was in possession -of the private identity key at the time the payload was generated. +payload](#the-libp2p--handshake-payload). This signature is produced with the +private libp2p identity key, which proves that the sender was in possession of +the private identity key at the time the payload was generated. ### libp2p Data in Handshake Messages @@ -206,11 +206,11 @@ been validated. If the handshake fails for any reason, the early data payload MUST be discarded immediately. Any early data provided to noise-libp2p MUST be included in the [signed -handshake payload](#the-libp2p-signed-handshake-payload) as a byte string -without alteration by the noise-libp2p implementation, and a valid signature of -the early data MUST be included as described below. +handshake payload](#the-libp2p-handshake-payload) as a byte string without +alteration by the noise-libp2p implementation, and a valid signature of the +early data MUST be included as described below. -#### The libp2p Signed Handshake Payload +#### The libp2p Handshake Payload libp2p-specific data, including the signature used for static key authentication, is transmitted in Noise handshake message payloads. When @@ -302,8 +302,8 @@ to the other party. The first handshake message contains the initiator's ephemeral public key, which allows subsequent key exchanges and message payloads to be encrypted. -The second and third handshake messages include a [signed handshake -payload](#the-libp2p-signed-handshake-payload), which contains a signature +The second and third handshake messages include a [Noise handshake +payload](#the-libp2p-handshake-payload), which contains a signature authenticating the sender's static Noise key as described in the [Static Key Authentication section](#static-key-authentication) and may include other internal libp2p data. @@ -377,8 +377,8 @@ key has changed, they may initiate an [`XXfallback`](#xxfallback) handshake, using the ephemeral public key from the failed `IK` handshake message as pre-message knowledge. -Each handshake message will include a [libp2p signed handshake -payload](#the-libp2p-signed-handshake-payload) that identifies the sender and +Each handshake message will include a [libp2p handshake +payload](#the-libp2p-handshake-payload) that identifies the sender and authenticates the static Noise key. #### XXfallback @@ -408,8 +408,8 @@ key is obtained from her initial `IK` message, moving it to the pre-message section of the handshake pattern. Essentially, the failed `IK` message serves the same role as the first handshake message in the standard `XX` pattern. -Each handshake message will include a [libp2p signed handshake -payload](#the-libp2p-signed-handshake-payload) that identifies the sender and +Each handshake message will include a [libp2p handshake +payload](#the-libp2p-handshake-payload) that identifies the sender and authenticates the static Noise key. #### Noise Pipes Message Flow @@ -489,7 +489,9 @@ and [SHA256 hash function][npf-hash-sha256] as defined in the Noise spec. ## Valid Noise Protocol Names This section lists the [Noise protocol names][npf-protocol-names] that are valid -according to the definitions in this spec. +according to the definitions in this spec. While these names are useful +internally when working with Noise, they are never sent "on the wire" or used +for any kind of handshake negotiation and are provided for reference. Because only a single set of cryptographic primitives is supported, the Noise protocol name depends on the handshake pattern in use. @@ -521,34 +523,18 @@ The `noise_message` field contains a [Noise Message as defined in the Noise spec][npf-message-format], which has a maximum length of 65535 bytes. During the handshake phase, `noise_message` will be a Noise handshake message. -Noise handshake messages may contain encrypted payloads. If so, they will have -the structure described in the [Encrypted Payloads -section](#encrypted-payloads). +Noise handshake messages may contain encrypted payloads. If so, the decrypted +handshake payload will have the format described in [The libp2p Hanshake +Payload](#the-libp2p-handshake-payload). After the handshake completes, `noise_message` will be a Noise transport message, which is defined as an AEAD ciphertext consisting of an encrypted payload plus 16 bytes of authentication data. The decrypted plaintext of the -encrypted payload will have the structure described in the [Encrypted Payloads -section](#encrypted-payloads). +encrypted payload will contain up to 65535 bytes of "application layer" data. +It is the responsibilty of the noise-libp2p implementation to segment +application data into chunks that will fit into a Noise transport message when +sending, and to buffer and recombine chunks when receiving. -### Encrypted Payloads - -All Noise transport messages have a single encrypted payload. Noise handshake -messages may or may not have an encrypted payload. - -Once decrypted, the plaintext of an encrypted payload will have this structure: - -| `body_len` | `body` | `padding` | -|------------|-----------------|-----------------| -| 2 bytes | variable length | variable length | - -The `body_len` field stores the length in bytes of the `body` field as an -unsigned 16-bit big-endian integer. - -All data following the `body` field consists of padding bytes, which must be -ignored by the recipient. Senders SHOULD use a source of random data to populate -the padding field and may use any length of padding that does not cause the -total length of the Noise message to exceed 65535 bytes. ## Encryption and I/O @@ -577,10 +563,12 @@ transport message, which is an AEAD ciphertext consisting of an encrypted payload plus 16 bytes of authentication data, as [defined in the Noise spec][npf-message-format]. -When decrypted, the payload of a Noise transport message will have the structure -described in [Encrypted Payloads](#encrypted-payloads). Receivers MUST decode -the `body_len` field from the decrypted payload, and MUST ignore any additional -padding following the `body` field. +When decrypted, the payload of a Noise transport message will contain up to +65535 bytes of plaintext "application layer" data. This should be buffered by +the reciever and exposed as a continuous readable stream of binary data. +Likewise, when sending data, the noise-libp2p module should expose a writable +streaming interface. The segmentation of data into Noise transport messages +should be "invisible" outside of the noise-libp2p module. In the unlikely event that peers exchange more than `2^64 - 1` messages, they MUST terminate the connection to avoid reusing nonces, in accordance with the From f314d3620e7931d15c2a8041571066471575f15a Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 9 Sep 2019 09:51:12 -0400 Subject: [PATCH 3/4] add future work section --- noise/README.md | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/noise/README.md b/noise/README.md index a86435144..99c025611 100644 --- a/noise/README.md +++ b/noise/README.md @@ -43,7 +43,6 @@ and spec status. - [Cryptographic Primitives](#cryptographic-primitives) - [Valid Noise Protocol Names](#valid-noise-protocol-names) - [Wire Format](#wire-format) - - [Encrypted Payloads](#encrypted-payloads) - [Encryption and I/O](#encryption-and-io) - [libp2p Interfaces and API](#libp2p-interfaces-and-api) - [Initialization](#initialization) @@ -56,6 +55,9 @@ and spec status. - [Why ChaChaPoly?](#why-chachapoly) - [Distinct Noise and Identity Keys](#distinct-noise-and-identity-keys) - [Why Not Noise Signatures?](#why-not-noise-signatures) + - [Future Work](#future-work) + - [QUIC Support](#quic-support) + - [Pre-shared Keys / Private Networking](#pre-shared-keys--private-networking) ## Overview @@ -734,6 +736,38 @@ to complete a Noise Signatures handshake. Also, only Ed25519 signatures are currently supported by the spec, while libp2p identity keys may be of other unsupported types like RSA. +## Future Work + +This section will outline some things we'd like to accomplish in the future but +were ommitted from this draft because the path forward isn't yet clear. + +### QUIC Support + +go-libp2p has recently added support for [QUIC][ietf-quic-spec], a UDP-based +protocol with many excellent properties, including native support for +multiplexing and encryption. The current QUIC draft spec uses TLS 1.3 to secure +connections. However, it is possible to extend QUIC to use Noise, as +demonstrated by [nQUIC][nquic-paper], an experimental variant of the QUIC spec. + +We would like to explore the possiblity of integrating the Noise handshake into +libp2p's QUIC transport. This would likely build upon the nQUIC work, and may +involve extending nQUIC to support more than the `IK` handshake specified in the +nQUIC paper. + +### Pre-shared Keys / Private Networking + +Noise supports a "psk" variant of all the fundamental handshake patterns, which +uses an additional pre-shared key to secure traffic. This could potentially +provide an alternative to the current [private networking][libp2p-psk-spec] +functionality in libp2p, in which a pre-shared key is used to encrypt all data +within a given libp2p network. + +The current libp2p private network feature operates independently of the secure +handshake protocol, encrypting all traffic even before the secure channel +protocol has been negotiated. As a result, using Noise to implement private +networks may require changes to internal libp2p APIs, the scope of which aren't +yet clear. + [peer-id-spec]: ../peer-ids/peer-ids.md [peer-id-spec-signing-rules]: ../peer-ids/peer-ids.md#how-keys-are-encoded-and-messages-signed @@ -763,3 +797,4 @@ unsupported types like RSA. [protobuf]: https://developers.google.com/protocol-buffers/ [noise-socket-spec]: https://github.com/noisesocket/spec [noise-signatures-spec]: https://github.com/noiseprotocol/noise_sig_spec/blob/master/output/noise_sig.pdf +[ietf-quic-spec]: https://datatracker.ietf.org/doc/draft-ietf-quic-transport/ From 728c6d17a7b3474eba8027c23e41b423d41f3d3e Mon Sep 17 00:00:00 2001 From: Yusef Napora Date: Mon, 9 Sep 2019 09:56:21 -0400 Subject: [PATCH 4/4] bump revision number & add changelog section --- noise/README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/noise/README.md b/noise/README.md index 99c025611..5fdd151a3 100644 --- a/noise/README.md +++ b/noise/README.md @@ -4,7 +4,7 @@ | Lifecycle Stage | Maturity | Status | Latest Revision | |-----------------|---------------|--------|-----------------| -| 1A | Working Draft | Active | r0, 2019-08-05 | +| 1A | Working Draft | Active | r1, 2019-09-09 | Authors: [@yusefnapora] @@ -58,6 +58,8 @@ and spec status. - [Future Work](#future-work) - [QUIC Support](#quic-support) - [Pre-shared Keys / Private Networking](#pre-shared-keys--private-networking) + - [Changelog](#changelog) + - [r1 - 2019-09-09](#r1---2019-09-09) ## Overview @@ -768,6 +770,15 @@ protocol has been negotiated. As a result, using Noise to implement private networks may require changes to internal libp2p APIs, the scope of which aren't yet clear. + +## Changelog + +### r1 - 2019-09-09 + +- removed the padding from the plaintext of encrypted payloads for simpler I/O +- added Future Work section +- a bit more context on Noise Pipes, including why you might not need it + [peer-id-spec]: ../peer-ids/peer-ids.md [peer-id-spec-signing-rules]: ../peer-ids/peer-ids.md#how-keys-are-encoded-and-messages-signed