From 0002da3738961cf93acc8da8867aa902cf3439bb Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 15:45:31 +1000 Subject: [PATCH 01/23] Don't export `Handshake` module --- transports/noise/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 1712176d7ef..cb6497372a3 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -58,13 +58,13 @@ mod io; mod protocol; pub use error::NoiseError; -pub use io::handshake; pub use io::handshake::{Handshake, IdentityExchange, RemoteIdentity}; pub use io::NoiseOutput; pub use protocol::{x25519::X25519, x25519_spec::X25519Spec}; pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey}; pub use protocol::{Protocol, ProtocolParams, IK, IX, XX}; +use crate::io::handshake; use futures::prelude::*; use libp2p_core::{identity, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo}; use std::pin::Pin; From 6022e59e032f0dcdf63c0587b099365991acd3ba Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 15:52:37 +1000 Subject: [PATCH 02/23] Inline handshake functions --- transports/noise/src/io/handshake.rs | 165 ++---------------- transports/noise/src/lib.rs | 241 +++++++++++++++++++++------ 2 files changed, 201 insertions(+), 205 deletions(-) diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index 35099ea84dc..b15066232f9 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -93,7 +93,9 @@ pub enum IdentityExchange { /// A future performing a Noise handshake pattern. pub struct Handshake( - Pin, NoiseOutput), NoiseError>> + Send>>, + pub(crate) Pin< + Box, NoiseOutput), NoiseError>> + Send>, + >, ); impl Future for Handshake { @@ -104,158 +106,11 @@ impl Future for Handshake { } } -/// Creates an authenticated Noise handshake for the initiator of a -/// single roundtrip (2 message) handshake pattern. -/// -/// Subject to the chosen [`IdentityExchange`], this message sequence -/// identifies the local node to the remote with the first message payload -/// (i.e. unencrypted) and expects the remote to identify itself in the -/// second message payload. -/// -/// This message sequence is suitable for authenticated 2-message Noise handshake -/// patterns where the static keys of the initiator and responder are either -/// known (i.e. appear in the pre-message pattern) or are sent with -/// the first and second message, respectively (e.g. `IK` or `IX`). -/// -/// ```raw -/// initiator -{id}-> responder -/// initiator <-{id}- responder -/// ``` -pub fn rt1_initiator( - io: T, - session: Result, - identity: KeypairIdentity, - identity_x: IdentityExchange, - legacy: LegacyConfig, -) -> Handshake -where - T: AsyncWrite + AsyncRead + Send + Unpin + 'static, - C: Protocol + AsRef<[u8]>, -{ - Handshake(Box::pin(async move { - let mut state = State::new(io, session, identity, identity_x, legacy)?; - send_identity(&mut state).await?; - recv_identity(&mut state).await?; - state.finish() - })) -} - -/// Creates an authenticated Noise handshake for the responder of a -/// single roundtrip (2 message) handshake pattern. -/// -/// Subject to the chosen [`IdentityExchange`], this message sequence expects the -/// remote to identify itself in the first message payload (i.e. unencrypted) -/// and identifies the local node to the remote in the second message payload. -/// -/// This message sequence is suitable for authenticated 2-message Noise handshake -/// patterns where the static keys of the initiator and responder are either -/// known (i.e. appear in the pre-message pattern) or are sent with the first -/// and second message, respectively (e.g. `IK` or `IX`). -/// -/// ```raw -/// initiator -{id}-> responder -/// initiator <-{id}- responder -/// ``` -pub fn rt1_responder( - io: T, - session: Result, - identity: KeypairIdentity, - identity_x: IdentityExchange, - legacy: LegacyConfig, -) -> Handshake -where - T: AsyncWrite + AsyncRead + Send + Unpin + 'static, - C: Protocol + AsRef<[u8]>, -{ - Handshake(Box::pin(async move { - let mut state = State::new(io, session, identity, identity_x, legacy)?; - recv_identity(&mut state).await?; - send_identity(&mut state).await?; - state.finish() - })) -} - -/// Creates an authenticated Noise handshake for the initiator of a -/// 1.5-roundtrip (3 message) handshake pattern. -/// -/// Subject to the chosen [`IdentityExchange`], this message sequence expects -/// the remote to identify itself in the second message payload and -/// identifies the local node to the remote in the third message payload. -/// The first (unencrypted) message payload is always empty. -/// -/// This message sequence is suitable for authenticated 3-message Noise handshake -/// patterns where the static keys of the responder and initiator are either known -/// (i.e. appear in the pre-message pattern) or are sent with the second and third -/// message, respectively (e.g. `XX`). -/// -/// ```raw -/// initiator --{}--> responder -/// initiator <-{id}- responder -/// initiator -{id}-> responder -/// ``` -pub fn rt15_initiator( - io: T, - session: Result, - identity: KeypairIdentity, - identity_x: IdentityExchange, - legacy: LegacyConfig, -) -> Handshake -where - T: AsyncWrite + AsyncRead + Unpin + Send + 'static, - C: Protocol + AsRef<[u8]>, -{ - Handshake(Box::pin(async move { - let mut state = State::new(io, session, identity, identity_x, legacy)?; - send_empty(&mut state).await?; - recv_identity(&mut state).await?; - send_identity(&mut state).await?; - state.finish() - })) -} - -/// Creates an authenticated Noise handshake for the responder of a -/// 1.5-roundtrip (3 message) handshake pattern. -/// -/// Subject to the chosen [`IdentityExchange`], this message sequence -/// identifies the local node in the second message payload and expects -/// the remote to identify itself in the third message payload. The first -/// (unencrypted) message payload is always empty. -/// -/// This message sequence is suitable for authenticated 3-message Noise handshake -/// patterns where the static keys of the responder and initiator are either known -/// (i.e. appear in the pre-message pattern) or are sent with the second and third -/// message, respectively (e.g. `XX`). -/// -/// ```raw -/// initiator --{}--> responder -/// initiator <-{id}- responder -/// initiator -{id}-> responder -/// ``` -pub fn rt15_responder( - io: T, - session: Result, - identity: KeypairIdentity, - identity_x: IdentityExchange, - legacy: LegacyConfig, -) -> Handshake -where - T: AsyncWrite + AsyncRead + Unpin + Send + 'static, - C: Protocol + AsRef<[u8]>, -{ - Handshake(Box::pin(async move { - let mut state = State::new(io, session, identity, identity_x, legacy)?; - recv_empty(&mut state).await?; - send_identity(&mut state).await?; - recv_identity(&mut state).await?; - state.finish() - })) -} - ////////////////////////////////////////////////////////////////////////////// // Internal /// Handshake state. -struct State { +pub struct State { /// The underlying I/O resource. io: NoiseFramed, /// The associated public identity of the local node's static DH keypair, @@ -277,7 +132,7 @@ impl State { /// will be sent and received on the given I/O resource and using the /// provided session for cryptographic operations according to the chosen /// Noise handshake pattern. - fn new( + pub fn new( io: T, session: Result, identity: KeypairIdentity, @@ -304,7 +159,7 @@ impl State { impl State { /// Finish a handshake, yielding the established remote identity and the /// [`NoiseOutput`] for communicating on the encrypted channel. - fn finish(self) -> Result<(RemoteIdentity, NoiseOutput), NoiseError> + pub fn finish(self) -> Result<(RemoteIdentity, NoiseOutput), NoiseError> where C: Protocol + AsRef<[u8]>, { @@ -340,7 +195,7 @@ where } /// A future for receiving a Noise handshake message with an empty payload. -async fn recv_empty(state: &mut State) -> Result<(), NoiseError> +pub async fn recv_empty(state: &mut State) -> Result<(), NoiseError> where T: AsyncRead + Unpin, { @@ -354,7 +209,7 @@ where } /// A future for sending a Noise handshake message with an empty payload. -async fn send_empty(state: &mut State) -> Result<(), NoiseError> +pub async fn send_empty(state: &mut State) -> Result<(), NoiseError> where T: AsyncWrite + Unpin, { @@ -364,7 +219,7 @@ where /// A future for receiving a Noise handshake message with a payload /// identifying the remote. -async fn recv_identity(state: &mut State) -> Result<(), NoiseError> +pub async fn recv_identity(state: &mut State) -> Result<(), NoiseError> where T: AsyncRead + Unpin, { @@ -421,7 +276,7 @@ where } /// Send a Noise handshake message with a payload identifying the local node to the remote. -async fn send_identity(state: &mut State) -> Result<(), NoiseError> +pub async fn send_identity(state: &mut State) -> Result<(), NoiseError> where T: AsyncWrite + Unpin, { diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index cb6497372a3..c8d7674f6b6 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -64,6 +64,7 @@ pub use protocol::{x25519::X25519, x25519_spec::X25519Spec}; pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey}; pub use protocol::{Protocol, ProtocolParams, IK, IX, XX}; +use crate::handshake::State; use crate::io::handshake; use futures::prelude::*; use libp2p_core::{identity, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo}; @@ -168,8 +169,23 @@ where } } -// Handshake pattern IX ///////////////////////////////////////////////////// - +/// TODO: Adapt +/// Creates an authenticated Noise handshake for the responder of a +/// single roundtrip (2 message) handshake pattern. +/// +/// Subject to the chosen [`IdentityExchange`], this message sequence expects the +/// remote to identify itself in the first message payload (i.e. unencrypted) +/// and identifies the local node to the remote in the second message payload. +/// +/// This message sequence is suitable for authenticated 2-message Noise handshake +/// patterns where the static keys of the initiator and responder are either +/// known (i.e. appear in the pre-message pattern) or are sent with the first +/// and second message, respectively (e.g. `IK` or `IX`). +/// +/// ```raw +/// initiator -{id}-> responder +/// initiator <-{id}- responder +/// ``` impl InboundUpgrade for NoiseConfig where NoiseConfig: UpgradeInfo, @@ -187,16 +203,40 @@ where .local_private_key(self.dh_keys.secret().as_ref()) .build_responder() .map_err(NoiseError::from); - handshake::rt1_responder( - socket, - session, - self.dh_keys.into_identity(), - IdentityExchange::Mutual, - self.legacy, - ) + + Handshake(Box::pin(async move { + let mut state = State::new( + socket, + session, + self.dh_keys.into_identity(), + IdentityExchange::Mutual, + self.legacy, + )?; + handshake::recv_identity(&mut state).await?; + handshake::send_identity(&mut state).await?; + state.finish() + })) } } +/// TODO: Adapt +/// Creates an authenticated Noise handshake for the initiator of a +/// single roundtrip (2 message) handshake pattern. +/// +/// Subject to the chosen [`IdentityExchange`], this message sequence +/// identifies the local node to the remote with the first message payload +/// (i.e. unencrypted) and expects the remote to identify itself in the +/// second message payload. +/// +/// This message sequence is suitable for authenticated 2-message Noise handshake +/// patterns where the static keys of the initiator and responder are either +/// known (i.e. appear in the pre-message pattern) or are sent with +/// the first and second message, respectively (e.g. `IK` or `IX`). +/// +/// ```raw +/// initiator -{id}-> responder +/// initiator <-{id}- responder +/// ``` impl OutboundUpgrade for NoiseConfig where NoiseConfig: UpgradeInfo, @@ -214,18 +254,41 @@ where .local_private_key(self.dh_keys.secret().as_ref()) .build_initiator() .map_err(NoiseError::from); - handshake::rt1_initiator( - socket, - session, - self.dh_keys.into_identity(), - IdentityExchange::Mutual, - self.legacy, - ) + + Handshake(Box::pin(async move { + let mut state = State::new( + socket, + session, + self.dh_keys.into_identity(), + IdentityExchange::Mutual, + self.legacy, + )?; + handshake::send_identity(&mut state).await?; + handshake::recv_identity(&mut state).await?; + state.finish() + })) } } -// Handshake pattern XX ///////////////////////////////////////////////////// - +/// TODO: Adapt +/// Creates an authenticated Noise handshake for the responder of a +/// 1.5-roundtrip (3 message) handshake pattern. +/// +/// Subject to the chosen [`IdentityExchange`], this message sequence +/// identifies the local node in the second message payload and expects +/// the remote to identify itself in the third message payload. The first +/// (unencrypted) message payload is always empty. +/// +/// This message sequence is suitable for authenticated 3-message Noise handshake +/// patterns where the static keys of the responder and initiator are either known +/// (i.e. appear in the pre-message pattern) or are sent with the second and third +/// message, respectively (e.g. `XX`). +/// +/// ```raw +/// initiator --{}--> responder +/// initiator <-{id}- responder +/// initiator -{id}-> responder +/// ``` impl InboundUpgrade for NoiseConfig where NoiseConfig: UpgradeInfo, @@ -243,16 +306,42 @@ where .local_private_key(self.dh_keys.secret().as_ref()) .build_responder() .map_err(NoiseError::from); - handshake::rt15_responder( - socket, - session, - self.dh_keys.into_identity(), - IdentityExchange::Mutual, - self.legacy, - ) + + Handshake(Box::pin(async move { + let mut state = State::new( + socket, + session, + self.dh_keys.into_identity(), + IdentityExchange::Mutual, + self.legacy, + )?; + handshake::recv_empty(&mut state).await?; + handshake::send_identity(&mut state).await?; + handshake::recv_identity(&mut state).await?; + state.finish() + })) } } +/// TODO: Adapt +/// Creates an authenticated Noise handshake for the initiator of a +/// 1.5-roundtrip (3 message) handshake pattern. +/// +/// Subject to the chosen [`IdentityExchange`], this message sequence expects +/// the remote to identify itself in the second message payload and +/// identifies the local node to the remote in the third message payload. +/// The first (unencrypted) message payload is always empty. +/// +/// This message sequence is suitable for authenticated 3-message Noise handshake +/// patterns where the static keys of the responder and initiator are either known +/// (i.e. appear in the pre-message pattern) or are sent with the second and third +/// message, respectively (e.g. `XX`). +/// +/// ```raw +/// initiator --{}--> responder +/// initiator <-{id}- responder +/// initiator -{id}-> responder +/// ``` impl OutboundUpgrade for NoiseConfig where NoiseConfig: UpgradeInfo, @@ -270,18 +359,40 @@ where .local_private_key(self.dh_keys.secret().as_ref()) .build_initiator() .map_err(NoiseError::from); - handshake::rt15_initiator( - socket, - session, - self.dh_keys.into_identity(), - IdentityExchange::Mutual, - self.legacy, - ) + + Handshake(Box::pin(async move { + let mut state = State::new( + socket, + session, + self.dh_keys.into_identity(), + IdentityExchange::Mutual, + self.legacy, + )?; + handshake::send_empty(&mut state).await?; + handshake::recv_identity(&mut state).await?; + handshake::send_identity(&mut state).await?; + state.finish() + })) } } -// Handshake pattern IK ///////////////////////////////////////////////////// - +/// TODO: Adapt +/// Creates an authenticated Noise handshake for the responder of a +/// single roundtrip (2 message) handshake pattern. +/// +/// Subject to the chosen [`IdentityExchange`], this message sequence expects the +/// remote to identify itself in the first message payload (i.e. unencrypted) +/// and identifies the local node to the remote in the second message payload. +/// +/// This message sequence is suitable for authenticated 2-message Noise handshake +/// patterns where the static keys of the initiator and responder are either +/// known (i.e. appear in the pre-message pattern) or are sent with the first +/// and second message, respectively (e.g. `IK` or `IX`). +/// +/// ```raw +/// initiator -{id}-> responder +/// initiator <-{id}- responder +/// ``` impl InboundUpgrade for NoiseConfig where NoiseConfig: UpgradeInfo, @@ -299,16 +410,40 @@ where .local_private_key(self.dh_keys.secret().as_ref()) .build_responder() .map_err(NoiseError::from); - handshake::rt1_responder( - socket, - session, - self.dh_keys.into_identity(), - IdentityExchange::Receive, - self.legacy, - ) + + Handshake(Box::pin(async move { + let mut state = State::new( + socket, + session, + self.dh_keys.into_identity(), + IdentityExchange::Receive, + self.legacy, + )?; + handshake::recv_identity(&mut state).await?; + handshake::send_identity(&mut state).await?; + state.finish() + })) } } +/// TODO: Adapt +/// Creates an authenticated Noise handshake for the initiator of a +/// single roundtrip (2 message) handshake pattern. +/// +/// Subject to the chosen [`IdentityExchange`], this message sequence +/// identifies the local node to the remote with the first message payload +/// (i.e. unencrypted) and expects the remote to identify itself in the +/// second message payload. +/// +/// This message sequence is suitable for authenticated 2-message Noise handshake +/// patterns where the static keys of the initiator and responder are either +/// known (i.e. appear in the pre-message pattern) or are sent with +/// the first and second message, respectively (e.g. `IK` or `IX`). +/// +/// ```raw +/// initiator -{id}-> responder +/// initiator <-{id}- responder +/// ``` impl OutboundUpgrade for NoiseConfig, identity::PublicKey)> where NoiseConfig, identity::PublicKey)>: UpgradeInfo, @@ -327,15 +462,21 @@ where .remote_public_key(self.remote.0.as_ref()) .build_initiator() .map_err(NoiseError::from); - handshake::rt1_initiator( - socket, - session, - self.dh_keys.into_identity(), - IdentityExchange::Send { - remote: self.remote.1, - }, - self.legacy, - ) + + Handshake(Box::pin(async move { + let mut state = State::new( + socket, + session, + self.dh_keys.into_identity(), + IdentityExchange::Send { + remote: self.remote.1, + }, + self.legacy, + )?; + handshake::send_identity(&mut state).await?; + handshake::recv_identity(&mut state).await?; + state.finish() + })) } } From e40ac56d9557a9409bd05a20b01c361052143ba8 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 15:54:31 +1000 Subject: [PATCH 03/23] Remove `Handshake` type in favor of BoxFuture --- transports/noise/src/io/handshake.rs | 18 +---------- transports/noise/src/lib.rs | 45 ++++++++++++++++------------ 2 files changed, 27 insertions(+), 36 deletions(-) diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index b15066232f9..b8188723f03 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -31,10 +31,9 @@ use crate::protocol::{KeypairIdentity, Protocol, PublicKey}; use crate::LegacyConfig; use bytes::Bytes; use futures::prelude::*; -use futures::task; use libp2p_core::identity; use prost::Message; -use std::{io, pin::Pin, task::Context}; +use std::io; /// The identity of the remote established during a handshake. pub enum RemoteIdentity { @@ -91,21 +90,6 @@ pub enum IdentityExchange { None { remote: identity::PublicKey }, } -/// A future performing a Noise handshake pattern. -pub struct Handshake( - pub(crate) Pin< - Box, NoiseOutput), NoiseError>> + Send>, - >, -); - -impl Future for Handshake { - type Output = Result<(RemoteIdentity, NoiseOutput), NoiseError>; - - fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> task::Poll { - Pin::new(&mut self.0).poll(ctx) - } -} - ////////////////////////////////////////////////////////////////////////////// // Internal diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index c8d7674f6b6..9b981e3bf1d 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -58,12 +58,13 @@ mod io; mod protocol; pub use error::NoiseError; -pub use io::handshake::{Handshake, IdentityExchange, RemoteIdentity}; +pub use io::handshake::{IdentityExchange, RemoteIdentity}; pub use io::NoiseOutput; pub use protocol::{x25519::X25519, x25519_spec::X25519Spec}; pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey}; pub use protocol::{Protocol, ProtocolParams, IK, IX, XX}; +use crate::future::BoxFuture; use crate::handshake::State; use crate::io::handshake; use futures::prelude::*; @@ -194,7 +195,7 @@ where { type Output = (RemoteIdentity, NoiseOutput); type Error = NoiseError; - type Future = Handshake; + type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { let session = self @@ -204,7 +205,7 @@ where .build_responder() .map_err(NoiseError::from); - Handshake(Box::pin(async move { + async move { let mut state = State::new( socket, session, @@ -215,7 +216,8 @@ where handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; state.finish() - })) + } + .boxed() } } @@ -245,7 +247,7 @@ where { type Output = (RemoteIdentity, NoiseOutput); type Error = NoiseError; - type Future = Handshake; + type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { let session = self @@ -255,7 +257,7 @@ where .build_initiator() .map_err(NoiseError::from); - Handshake(Box::pin(async move { + async move { let mut state = State::new( socket, session, @@ -266,7 +268,8 @@ where handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; state.finish() - })) + } + .boxed() } } @@ -297,7 +300,7 @@ where { type Output = (RemoteIdentity, NoiseOutput); type Error = NoiseError; - type Future = Handshake; + type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { let session = self @@ -307,7 +310,7 @@ where .build_responder() .map_err(NoiseError::from); - Handshake(Box::pin(async move { + async move { let mut state = State::new( socket, session, @@ -319,7 +322,8 @@ where handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; state.finish() - })) + } + .boxed() } } @@ -350,7 +354,7 @@ where { type Output = (RemoteIdentity, NoiseOutput); type Error = NoiseError; - type Future = Handshake; + type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { let session = self @@ -360,7 +364,7 @@ where .build_initiator() .map_err(NoiseError::from); - Handshake(Box::pin(async move { + async move { let mut state = State::new( socket, session, @@ -372,7 +376,8 @@ where handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; state.finish() - })) + } + .boxed() } } @@ -401,7 +406,7 @@ where { type Output = (RemoteIdentity, NoiseOutput); type Error = NoiseError; - type Future = Handshake; + type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { let session = self @@ -411,7 +416,7 @@ where .build_responder() .map_err(NoiseError::from); - Handshake(Box::pin(async move { + async move { let mut state = State::new( socket, session, @@ -422,7 +427,8 @@ where handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; state.finish() - })) + } + .boxed() } } @@ -452,7 +458,7 @@ where { type Output = (RemoteIdentity, NoiseOutput); type Error = NoiseError; - type Future = Handshake; + type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { let session = self @@ -463,7 +469,7 @@ where .build_initiator() .map_err(NoiseError::from); - Handshake(Box::pin(async move { + async move { let mut state = State::new( socket, session, @@ -476,7 +482,8 @@ where handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; state.finish() - })) + } + .boxed() } } From ea42fe3e8d629576028140c08d5dcd76fc25956b Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 15:55:40 +1000 Subject: [PATCH 04/23] Move construction of session into future --- transports/noise/src/lib.rs | 86 ++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 9b981e3bf1d..15cfab31625 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -198,14 +198,14 @@ where type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) - .build_responder() - .map_err(NoiseError::from); - async move { + let session = self + .params + .into_builder() + .local_private_key(self.dh_keys.secret().as_ref()) + .build_responder() + .map_err(NoiseError::from); + let mut state = State::new( socket, session, @@ -250,14 +250,14 @@ where type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) - .build_initiator() - .map_err(NoiseError::from); - async move { + let session = self + .params + .into_builder() + .local_private_key(self.dh_keys.secret().as_ref()) + .build_initiator() + .map_err(NoiseError::from); + let mut state = State::new( socket, session, @@ -303,14 +303,14 @@ where type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) - .build_responder() - .map_err(NoiseError::from); - async move { + let session = self + .params + .into_builder() + .local_private_key(self.dh_keys.secret().as_ref()) + .build_responder() + .map_err(NoiseError::from); + let mut state = State::new( socket, session, @@ -357,14 +357,14 @@ where type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) - .build_initiator() - .map_err(NoiseError::from); - async move { + let session = self + .params + .into_builder() + .local_private_key(self.dh_keys.secret().as_ref()) + .build_initiator() + .map_err(NoiseError::from); + let mut state = State::new( socket, session, @@ -409,14 +409,14 @@ where type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) - .build_responder() - .map_err(NoiseError::from); - async move { + let session = self + .params + .into_builder() + .local_private_key(self.dh_keys.secret().as_ref()) + .build_responder() + .map_err(NoiseError::from); + let mut state = State::new( socket, session, @@ -461,15 +461,15 @@ where type Future = BoxFuture<'static, Result<(RemoteIdentity, NoiseOutput), NoiseError>>; fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) - .remote_public_key(self.remote.0.as_ref()) - .build_initiator() - .map_err(NoiseError::from); - async move { + let session = self + .params + .into_builder() + .local_private_key(self.dh_keys.secret().as_ref()) + .remote_public_key(self.remote.0.as_ref()) + .build_initiator() + .map_err(NoiseError::from); + let mut state = State::new( socket, session, From bdb66783939a1585b351c8723daf5d780c1e0546 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 15:58:15 +1000 Subject: [PATCH 05/23] Make better use of `?` --- transports/noise/src/io/handshake.rs | 11 +++++----- transports/noise/src/lib.rs | 30 +++++++++++----------------- 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index b8188723f03..804376501ab 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -118,25 +118,26 @@ impl State { /// Noise handshake pattern. pub fn new( io: T, - session: Result, + session: snow::HandshakeState, identity: KeypairIdentity, identity_x: IdentityExchange, legacy: LegacyConfig, - ) -> Result { + ) -> Self { let (id_remote_pubkey, send_identity) = match identity_x { IdentityExchange::Mutual => (None, true), IdentityExchange::Send { remote } => (Some(remote), true), IdentityExchange::Receive => (None, false), IdentityExchange::None { remote } => (Some(remote), false), }; - session.map(|s| State { + + Self { identity, - io: NoiseFramed::new(io, s), + io: NoiseFramed::new(io, session), dh_remote_pubkey_sig: None, id_remote_pubkey, send_identity, legacy, - }) + } } } diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 15cfab31625..ee8ff50b25c 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -203,8 +203,7 @@ where .params .into_builder() .local_private_key(self.dh_keys.secret().as_ref()) - .build_responder() - .map_err(NoiseError::from); + .build_responder()?; let mut state = State::new( socket, @@ -212,7 +211,7 @@ where self.dh_keys.into_identity(), IdentityExchange::Mutual, self.legacy, - )?; + ); handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; state.finish() @@ -255,8 +254,7 @@ where .params .into_builder() .local_private_key(self.dh_keys.secret().as_ref()) - .build_initiator() - .map_err(NoiseError::from); + .build_initiator()?; let mut state = State::new( socket, @@ -264,7 +262,7 @@ where self.dh_keys.into_identity(), IdentityExchange::Mutual, self.legacy, - )?; + ); handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; state.finish() @@ -308,8 +306,7 @@ where .params .into_builder() .local_private_key(self.dh_keys.secret().as_ref()) - .build_responder() - .map_err(NoiseError::from); + .build_responder()?; let mut state = State::new( socket, @@ -317,7 +314,7 @@ where self.dh_keys.into_identity(), IdentityExchange::Mutual, self.legacy, - )?; + ); handshake::recv_empty(&mut state).await?; handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; @@ -362,8 +359,7 @@ where .params .into_builder() .local_private_key(self.dh_keys.secret().as_ref()) - .build_initiator() - .map_err(NoiseError::from); + .build_initiator()?; let mut state = State::new( socket, @@ -371,7 +367,7 @@ where self.dh_keys.into_identity(), IdentityExchange::Mutual, self.legacy, - )?; + ); handshake::send_empty(&mut state).await?; handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; @@ -414,8 +410,7 @@ where .params .into_builder() .local_private_key(self.dh_keys.secret().as_ref()) - .build_responder() - .map_err(NoiseError::from); + .build_responder()?; let mut state = State::new( socket, @@ -423,7 +418,7 @@ where self.dh_keys.into_identity(), IdentityExchange::Receive, self.legacy, - )?; + ); handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; state.finish() @@ -467,8 +462,7 @@ where .into_builder() .local_private_key(self.dh_keys.secret().as_ref()) .remote_public_key(self.remote.0.as_ref()) - .build_initiator() - .map_err(NoiseError::from); + .build_initiator()?; let mut state = State::new( socket, @@ -478,7 +472,7 @@ where remote: self.remote.1, }, self.legacy, - )?; + ); handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; state.finish() From 18e6eb4e54f6d1d8cdf49dd6c35d9d1916435c40 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 16:38:54 +1000 Subject: [PATCH 06/23] Remove `IdentityExchange` This is better expressed statically in code, tied to the actual handshake pattern. --- transports/noise/src/io/handshake.rs | 73 ++++++++++++---------------- transports/noise/src/lib.rs | 18 +++---- 2 files changed, 39 insertions(+), 52 deletions(-) diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index 804376501ab..d5cb68d038a 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -62,34 +62,6 @@ pub enum RemoteIdentity { IdentityKey(identity::PublicKey), } -/// The options for identity exchange in an authenticated handshake. -/// -/// > **Note**: Even if a remote's public identity key is known a priori, -/// > unless the authenticity of the key is [linked](Protocol::linked) to -/// > the authenticity of a remote's static DH public key, an authenticated -/// > handshake will still send the associated signature of the provided -/// > local [`KeypairIdentity`] in order for the remote to verify that the static -/// > DH public key is authentic w.r.t. the known public identity key. -pub enum IdentityExchange { - /// Send the local public identity to the remote. - /// - /// The remote identity is unknown (i.e. expected to be received). - Mutual, - /// Send the local public identity to the remote. - /// - /// The remote identity is known. - Send { remote: identity::PublicKey }, - /// Don't send the local public identity to the remote. - /// - /// The remote identity is unknown, i.e. expected to be received. - Receive, - /// Don't send the local public identity to the remote. - /// - /// The remote identity is known, thus identities must be mutually known - /// in order for the handshake to succeed. - None { remote: identity::PublicKey }, -} - ////////////////////////////////////////////////////////////////////////////// // Internal @@ -104,8 +76,6 @@ pub struct State { dh_remote_pubkey_sig: Option>, /// The known or received public identity key of the remote, if any. id_remote_pubkey: Option, - /// Whether to send the public identity key of the local node to the remote. - send_identity: bool, /// Legacy configuration parameters. legacy: LegacyConfig, } @@ -120,22 +90,14 @@ impl State { io: T, session: snow::HandshakeState, identity: KeypairIdentity, - identity_x: IdentityExchange, + expected_remote_key: Option, legacy: LegacyConfig, ) -> Self { - let (id_remote_pubkey, send_identity) = match identity_x { - IdentityExchange::Mutual => (None, true), - IdentityExchange::Send { remote } => (Some(remote), true), - IdentityExchange::Receive => (None, false), - IdentityExchange::None { remote } => (Some(remote), false), - }; - Self { identity, io: NoiseFramed::new(io, session), dh_remote_pubkey_sig: None, - id_remote_pubkey, - send_identity, + id_remote_pubkey: expected_remote_key, legacy, } } @@ -204,6 +166,9 @@ where /// A future for receiving a Noise handshake message with a payload /// identifying the remote. +/// +/// In case `expected_key` is passed, this function will fail if the received key does not match the expected key. +/// In case the remote does not send us a key, the expected key is assumed to be the remote's key. pub async fn recv_identity(state: &mut State) -> Result<(), NoiseError> where T: AsyncRead + Unpin, @@ -267,10 +232,34 @@ where { let mut pb = payload_proto::NoiseHandshakePayload::default(); - if state.send_identity { - pb.identity_key = state.identity.public.to_protobuf_encoding() + pb.identity_key = state.identity.public.to_protobuf_encoding(); + + if let Some(ref sig) = state.identity.signature { + pb.identity_sig = sig.clone() } + let mut msg = if state.legacy.send_legacy_handshake { + let mut msg = Vec::with_capacity(2 + pb.encoded_len()); + msg.extend_from_slice(&(pb.encoded_len() as u16).to_be_bytes()); + msg + } else { + Vec::with_capacity(pb.encoded_len()) + }; + + pb.encode(&mut msg) + .expect("Vec provides capacity as needed"); + state.io.send(&msg).await?; + + Ok(()) +} + +/// Send a Noise handshake message with a payload identifying the local node to the remote. +pub async fn send_signature_only(state: &mut State) -> Result<(), NoiseError> +where + T: AsyncWrite + Unpin, +{ + let mut pb = payload_proto::NoiseHandshakePayload::default(); + if let Some(ref sig) = state.identity.signature { pb.identity_sig = sig.clone() } diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index ee8ff50b25c..2491919f302 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -58,7 +58,7 @@ mod io; mod protocol; pub use error::NoiseError; -pub use io::handshake::{IdentityExchange, RemoteIdentity}; +pub use io::handshake::RemoteIdentity; pub use io::NoiseOutput; pub use protocol::{x25519::X25519, x25519_spec::X25519Spec}; pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey}; @@ -209,7 +209,7 @@ where socket, session, self.dh_keys.into_identity(), - IdentityExchange::Mutual, + None, self.legacy, ); handshake::recv_identity(&mut state).await?; @@ -260,7 +260,7 @@ where socket, session, self.dh_keys.into_identity(), - IdentityExchange::Mutual, + None, self.legacy, ); handshake::send_identity(&mut state).await?; @@ -312,7 +312,7 @@ where socket, session, self.dh_keys.into_identity(), - IdentityExchange::Mutual, + None, self.legacy, ); handshake::recv_empty(&mut state).await?; @@ -365,7 +365,7 @@ where socket, session, self.dh_keys.into_identity(), - IdentityExchange::Mutual, + None, self.legacy, ); handshake::send_empty(&mut state).await?; @@ -416,11 +416,11 @@ where socket, session, self.dh_keys.into_identity(), - IdentityExchange::Receive, + None, self.legacy, ); handshake::recv_identity(&mut state).await?; - handshake::send_identity(&mut state).await?; + handshake::send_signature_only(&mut state).await?; state.finish() } .boxed() @@ -468,9 +468,7 @@ where socket, session, self.dh_keys.into_identity(), - IdentityExchange::Send { - remote: self.remote.1, - }, + Some(self.remote.1), self.legacy, ); handshake::send_identity(&mut state).await?; From 7d0c18a5d6dcfbf5ccfd5bada692fa3624e560c4 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 16:43:27 +1000 Subject: [PATCH 07/23] Don't use Deref for things that are not smart pointers --- transports/noise/src/lib.rs | 12 ++++++------ transports/noise/src/protocol.rs | 12 ++++-------- transports/noise/tests/smoke.rs | 2 +- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 2491919f302..4b0b790848a 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -202,7 +202,7 @@ where let session = self .params .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) + .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) .build_responder()?; let mut state = State::new( @@ -253,7 +253,7 @@ where let session = self .params .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) + .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) .build_initiator()?; let mut state = State::new( @@ -305,7 +305,7 @@ where let session = self .params .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) + .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) .build_responder()?; let mut state = State::new( @@ -358,7 +358,7 @@ where let session = self .params .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) + .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) .build_initiator()?; let mut state = State::new( @@ -409,7 +409,7 @@ where let session = self .params .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) + .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) .build_responder()?; let mut state = State::new( @@ -460,7 +460,7 @@ where let session = self .params .into_builder() - .local_private_key(self.dh_keys.secret().as_ref()) + .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) .remote_public_key(self.remote.0.as_ref()) .build_initiator()?; diff --git a/transports/noise/src/protocol.rs b/transports/noise/src/protocol.rs index aa2acb150a9..b947f16498b 100644 --- a/transports/noise/src/protocol.rs +++ b/transports/noise/src/protocol.rs @@ -123,6 +123,10 @@ pub struct AuthenticKeypair { } impl AuthenticKeypair { + pub fn dh_keypair(&self) -> &Keypair { + &self.keypair + } + /// Extract the public [`KeypairIdentity`] from this `AuthenticKeypair`, /// dropping the DH `Keypair`. pub fn into_identity(self) -> KeypairIdentity { @@ -130,14 +134,6 @@ impl AuthenticKeypair { } } -impl std::ops::Deref for AuthenticKeypair { - type Target = Keypair; - - fn deref(&self) -> &Self::Target { - &self.keypair - } -} - /// The associated public identity of a DH keypair. #[derive(Clone)] pub struct KeypairIdentity { diff --git a/transports/noise/tests/smoke.rs b/transports/noise/tests/smoke.rs index 14d09621dd9..4812784ae0d 100644 --- a/transports/noise/tests/smoke.rs +++ b/transports/noise/tests/smoke.rs @@ -197,7 +197,7 @@ fn ik_xx() { let client_id_public = client_id.public(); let server_dh = Keypair::::new().into_authentic(&server_id).unwrap(); - let server_dh_public = server_dh.public().clone(); + let server_dh_public = server_dh.dh_keypair().public().clone(); let server_transport = TcpTransport::default() .and_then(move |output, endpoint| { if endpoint.is_listener() { From 269c821e0a5d78318f6af8931ef663b9037baec5 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 16:45:40 +1000 Subject: [PATCH 08/23] Drop unnecessary generic parameter Remote-key for IK listener is always `()`. --- transports/noise/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 4b0b790848a..6953d15379e 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -394,9 +394,9 @@ where /// initiator -{id}-> responder /// initiator <-{id}- responder /// ``` -impl InboundUpgrade for NoiseConfig +impl InboundUpgrade for NoiseConfig where - NoiseConfig: UpgradeInfo, + NoiseConfig: UpgradeInfo, T: AsyncRead + AsyncWrite + Unpin + Send + 'static, C: Protocol + AsRef<[u8]> + Zeroize + Send + 'static, { From 4b16a45d232f4660f9dba89bfd6b852e46b66a29 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 16:56:30 +1000 Subject: [PATCH 09/23] Adopt docs --- transports/noise/src/lib.rs | 90 +++++++++---------------------------- 1 file changed, 22 insertions(+), 68 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 6953d15379e..c1e4a1c69ec 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -170,18 +170,9 @@ where } } -/// TODO: Adapt -/// Creates an authenticated Noise handshake for the responder of a -/// single roundtrip (2 message) handshake pattern. +/// Implements the responder part of the `IX` noise handshake pattern. /// -/// Subject to the chosen [`IdentityExchange`], this message sequence expects the -/// remote to identify itself in the first message payload (i.e. unencrypted) -/// and identifies the local node to the remote in the second message payload. -/// -/// This message sequence is suitable for authenticated 2-message Noise handshake -/// patterns where the static keys of the initiator and responder are either -/// known (i.e. appear in the pre-message pattern) or are sent with the first -/// and second message, respectively (e.g. `IK` or `IX`). +/// `IX` is a single round-trip (2 messages) handshake in which each party sends their identity over to the other party. /// /// ```raw /// initiator -{id}-> responder @@ -220,19 +211,9 @@ where } } -/// TODO: Adapt -/// Creates an authenticated Noise handshake for the initiator of a -/// single roundtrip (2 message) handshake pattern. -/// -/// Subject to the chosen [`IdentityExchange`], this message sequence -/// identifies the local node to the remote with the first message payload -/// (i.e. unencrypted) and expects the remote to identify itself in the -/// second message payload. +/// Implements the initiator part of the `IX` noise handshake pattern. /// -/// This message sequence is suitable for authenticated 2-message Noise handshake -/// patterns where the static keys of the initiator and responder are either -/// known (i.e. appear in the pre-message pattern) or are sent with -/// the first and second message, respectively (e.g. `IK` or `IX`). +/// `IX` is a single round-trip (2 messages) handshake in which each party sends their identity over to the other party. /// /// ```raw /// initiator -{id}-> responder @@ -271,19 +252,12 @@ where } } -/// TODO: Adapt -/// Creates an authenticated Noise handshake for the responder of a -/// 1.5-roundtrip (3 message) handshake pattern. +/// Implements the responder part of the `XX` noise handshake pattern. /// -/// Subject to the chosen [`IdentityExchange`], this message sequence -/// identifies the local node in the second message payload and expects -/// the remote to identify itself in the third message payload. The first -/// (unencrypted) message payload is always empty. -/// -/// This message sequence is suitable for authenticated 3-message Noise handshake -/// patterns where the static keys of the responder and initiator are either known -/// (i.e. appear in the pre-message pattern) or are sent with the second and third -/// message, respectively (e.g. `XX`). +/// `XX` is a 1.5 round-trip (3 messages) handshake. +/// The first message in a noise handshake is unencrypted. In the `XX` handshake pattern, that message +/// is empty and thus does not leak and information. The identities are then exchanged in the second +/// and third message. /// /// ```raw /// initiator --{}--> responder @@ -324,19 +298,12 @@ where } } -/// TODO: Adapt -/// Creates an authenticated Noise handshake for the initiator of a -/// 1.5-roundtrip (3 message) handshake pattern. -/// -/// Subject to the chosen [`IdentityExchange`], this message sequence expects -/// the remote to identify itself in the second message payload and -/// identifies the local node to the remote in the third message payload. -/// The first (unencrypted) message payload is always empty. +/// Implements the initiator part of the `XX` noise handshake pattern. /// -/// This message sequence is suitable for authenticated 3-message Noise handshake -/// patterns where the static keys of the responder and initiator are either known -/// (i.e. appear in the pre-message pattern) or are sent with the second and third -/// message, respectively (e.g. `XX`). +/// `XX` is a 1.5 round-trip (3 messages) handshake. +/// The first message in a noise handshake is unencrypted. In the `XX` handshake pattern, that message +/// is empty and thus does not leak and information. The identities are then exchanged in the second +/// and third message. /// /// ```raw /// initiator --{}--> responder @@ -377,18 +344,12 @@ where } } -/// TODO: Adapt -/// Creates an authenticated Noise handshake for the responder of a -/// single roundtrip (2 message) handshake pattern. +/// Implements the responder part of the `IK` handshake pattern. /// -/// Subject to the chosen [`IdentityExchange`], this message sequence expects the -/// remote to identify itself in the first message payload (i.e. unencrypted) -/// and identifies the local node to the remote in the second message payload. +/// `IK` is a single round-trip (2 messages) handshake. /// -/// This message sequence is suitable for authenticated 2-message Noise handshake -/// patterns where the static keys of the initiator and responder are either -/// known (i.e. appear in the pre-message pattern) or are sent with the first -/// and second message, respectively (e.g. `IK` or `IX`). +/// In the `IK` handshake, the initiator is expected to know the responder's identity already, which +/// is why the responder does not send it in the second message. /// /// ```raw /// initiator -{id}-> responder @@ -427,19 +388,12 @@ where } } -/// TODO: Adapt -/// Creates an authenticated Noise handshake for the initiator of a -/// single roundtrip (2 message) handshake pattern. +/// Implements the initiator part of the `IK` handshake pattern. /// -/// Subject to the chosen [`IdentityExchange`], this message sequence -/// identifies the local node to the remote with the first message payload -/// (i.e. unencrypted) and expects the remote to identify itself in the -/// second message payload. +/// `IK` is a single round-trip (2 messages) handshake. /// -/// This message sequence is suitable for authenticated 2-message Noise handshake -/// patterns where the static keys of the initiator and responder are either -/// known (i.e. appear in the pre-message pattern) or are sent with -/// the first and second message, respectively (e.g. `IK` or `IX`). +/// In the `IK` handshake, the initiator knows and pre-configures the remote's identity in the +/// [`HandshakeState`]. /// /// ```raw /// initiator -{id}-> responder From 5072674149cd89e9369d1db616706ae78ba8f00b Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 16:59:26 +1000 Subject: [PATCH 10/23] Add changelog entry and bump version --- CHANGELOG.md | 2 ++ Cargo.toml | 2 +- transports/noise/CHANGELOG.md | 5 ++++- transports/noise/Cargo.toml | 2 +- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0332b09b316..734f8ff0d16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -51,6 +51,8 @@ - Update to [`libp2p-kad` `v0.41.0`](protocols/kad/CHANGELOG.md#0410). +- Update to [`libp2p-noise` `v0.40.0`](protocols/kad/CHANGELOG.md#0400). + # 0.48.0 - Update to [`libp2p-core` `v0.36.0`](core/CHANGELOG.md#0360). diff --git a/Cargo.toml b/Cargo.toml index 0b67edda7f3..71fb8dc45eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ libp2p-identify = { version = "0.39.0", path = "protocols/identify", optional = libp2p-kad = { version = "0.41.0", path = "protocols/kad", optional = true } libp2p-metrics = { version = "0.10.0", path = "misc/metrics", optional = true } libp2p-mplex = { version = "0.36.0", path = "muxers/mplex", optional = true } -libp2p-noise = { version = "0.39.1", path = "transports/noise", optional = true } +libp2p-noise = { version = "0.40.0", path = "transports/noise", optional = true } libp2p-ping = { version = "0.39.0", path = "protocols/ping", optional = true } libp2p-plaintext = { version = "0.36.0", path = "transports/plaintext", optional = true } libp2p-pnet = { version = "0.22.0", path = "transports/pnet", optional = true } diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index 1416aab4e30..a26a28c9081 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -1,9 +1,12 @@ -# 0.39.1 [unreleased] +# 0.40.0 [unreleased] - Introduce `NoiseAuthenticated::xx` constructor, assuming a X25519 DH key exchange. An XX key exchange and X25519 keys are the most common way of using noise in libp2p and thus deserve a convenience constructor. See [PR 2887]. +- Remove `Deref` implementation on `AuthenticKeypair`. See [PR XXXX]. +- Make `handshake` module private. See [PR XXXX]. [PR 2887]: https://github.com/libp2p/rust-libp2p/pull/2887 +[PR XXXX]: https://github.com/libp2p/rust-libp2p/pull/XXXX # 0.39.0 diff --git a/transports/noise/Cargo.toml b/transports/noise/Cargo.toml index 8fef520cb9a..5ac9e95609a 100644 --- a/transports/noise/Cargo.toml +++ b/transports/noise/Cargo.toml @@ -3,7 +3,7 @@ name = "libp2p-noise" edition = "2021" rust-version = "1.56.1" description = "Cryptographic handshake protocol using the noise framework." -version = "0.39.1" +version = "0.40.0" authors = ["Parity Technologies "] license = "MIT" repository = "https://github.com/libp2p/rust-libp2p" From 302a4ab60c3234882b3c98f06cd8b208531c50ce Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 17:04:14 +1000 Subject: [PATCH 11/23] Update transports/noise/CHANGELOG.md --- transports/noise/CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index a26a28c9081..04b4b708378 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -2,11 +2,11 @@ - Introduce `NoiseAuthenticated::xx` constructor, assuming a X25519 DH key exchange. An XX key exchange and X25519 keys are the most common way of using noise in libp2p and thus deserve a convenience constructor. See [PR 2887]. -- Remove `Deref` implementation on `AuthenticKeypair`. See [PR XXXX]. -- Make `handshake` module private. See [PR XXXX]. +- Remove `Deref` implementation on `AuthenticKeypair`. See [PR 2909]. +- Make `handshake` module private. See [PR 2909]. [PR 2887]: https://github.com/libp2p/rust-libp2p/pull/2887 -[PR XXXX]: https://github.com/libp2p/rust-libp2p/pull/XXXX +[PR 2909]: https://github.com/libp2p/rust-libp2p/pull/2909 # 0.39.0 From 53638b9de8347d61f922b6cdd0583da7d8f5f193 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 17:08:24 +1000 Subject: [PATCH 12/23] Fix clippy warning --- transports/noise/src/io/handshake.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/transports/noise/src/io/handshake.rs b/transports/noise/src/io/handshake.rs index d5cb68d038a..c32eef9690f 100644 --- a/transports/noise/src/io/handshake.rs +++ b/transports/noise/src/io/handshake.rs @@ -230,9 +230,10 @@ pub async fn send_identity(state: &mut State) -> Result<(), NoiseError> where T: AsyncWrite + Unpin, { - let mut pb = payload_proto::NoiseHandshakePayload::default(); - - pb.identity_key = state.identity.public.to_protobuf_encoding(); + let mut pb = payload_proto::NoiseHandshakePayload { + identity_key: state.identity.public.to_protobuf_encoding(), + ..Default::default() + }; if let Some(ref sig) = state.identity.signature { pb.identity_sig = sig.clone() From 39552a2c68dddadf93ce7c09f92a95304d367aae Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 16 Sep 2022 17:22:08 +1000 Subject: [PATCH 13/23] Fix doc links --- transports/noise/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index c1e4a1c69ec..8467f44b9c1 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -393,7 +393,7 @@ where /// `IK` is a single round-trip (2 messages) handshake. /// /// In the `IK` handshake, the initiator knows and pre-configures the remote's identity in the -/// [`HandshakeState`]. +/// [`HandshakeState`](snow::HandshakeState). /// /// ```raw /// initiator -{id}-> responder From ae18dd7ed600d0c692153b5a48d21d0442cf6e44 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Mon, 26 Sep 2022 11:12:02 +1000 Subject: [PATCH 14/23] Move `into_{responder,initiator}` to `ProtocolParams` This allows us to reuse them in all places. --- transports/noise/src/lib.rs | 140 +++++++------------------------ transports/noise/src/protocol.rs | 90 +++++++++++++++++++- 2 files changed, 117 insertions(+), 113 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index c3514e65124..5b324a81c67 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -69,7 +69,6 @@ use crate::handshake::State; use crate::io::handshake; use futures::prelude::*; use libp2p_core::{identity, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo}; -use snow::HandshakeState; use std::pin::Pin; use zeroize::Zeroize; @@ -110,35 +109,6 @@ impl NoiseConfig { } } -impl NoiseConfig -where - C: Zeroize + AsRef<[u8]>, -{ - fn into_responder(self) -> Result { - let state = self - .params - .into_builder() - .prologue(self.prologue.as_ref()) - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .build_responder() - .map_err(NoiseError::from)?; - - Ok(state) - } - - fn into_initiator(self) -> Result { - let state = self - .params - .into_builder() - .prologue(self.prologue.as_ref()) - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .build_initiator() - .map_err(NoiseError::from)?; - - Ok(state) - } -} - impl NoiseConfig where C: Protocol + Zeroize, @@ -237,11 +207,11 @@ where fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .build_responder()?; + let session = self.params.into_responder( + &self.prologue, + self.dh_keys.dh_keypair().secret(), + None, + )?; let mut state = State::new( socket, @@ -278,11 +248,11 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .build_initiator()?; + let session = self.params.into_responder( + &self.prologue, + self.dh_keys.dh_keypair().secret(), + None, + )?; let mut state = State::new( socket, @@ -323,11 +293,11 @@ where fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .build_responder()?; + let session = self.params.into_responder( + &self.prologue, + self.dh_keys.dh_keypair().secret(), + None, + )?; let mut state = State::new( socket, @@ -369,11 +339,11 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .build_initiator()?; + let session = self.params.into_responder( + &self.prologue, + self.dh_keys.dh_keypair().secret(), + None, + )?; let mut state = State::new( socket, @@ -414,11 +384,11 @@ where fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self - .params - .into_builder() - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .build_responder()?; + let session = self.params.into_responder( + &self.prologue, + self.dh_keys.dh_keypair().secret(), + None, + )?; let mut state = State::new( socket, @@ -458,13 +428,11 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self - .params - .into_builder() - .prologue(self.prologue.as_ref()) - .local_private_key(self.dh_keys.dh_keypair().secret().as_ref()) - .remote_public_key(self.remote.0.as_ref()) - .build_initiator()?; + let session = self.params.into_initiator( + &self.prologue, + self.dh_keys.dh_keypair().secret(), + Some(&self.remote.0), + )?; let mut state = State::new( socket, @@ -587,51 +555,3 @@ pub struct LegacyConfig { /// libp2p implementations. pub recv_legacy_handshake: bool, } - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn handshake_hashes_disagree_if_prologue_differs() { - let alice = new_xx_config() - .with_prologue(b"alice prologue".to_vec()) - .into_initiator() - .unwrap(); - let bob = new_xx_config() - .with_prologue(b"bob prologue".to_vec()) - .into_responder() - .unwrap(); - - let alice_handshake_hash = alice.get_handshake_hash(); - let bob_handshake_hash = bob.get_handshake_hash(); - - assert_ne!(alice_handshake_hash, bob_handshake_hash) - } - - #[test] - fn handshake_hashes_agree_if_prologue_is_the_same() { - let alice = new_xx_config() - .with_prologue(b"shared knowledge".to_vec()) - .into_initiator() - .unwrap(); - let bob = new_xx_config() - .with_prologue(b"shared knowledge".to_vec()) - .into_responder() - .unwrap(); - - let alice_handshake_hash = alice.get_handshake_hash(); - let bob_handshake_hash = bob.get_handshake_hash(); - - assert_eq!(alice_handshake_hash, bob_handshake_hash) - } - - fn new_xx_config() -> NoiseConfig { - let dh_keys = Keypair::::new(); - let noise_keys = dh_keys - .into_authentic(&identity::Keypair::generate_ed25519()) - .unwrap(); - - NoiseConfig::xx(noise_keys) - } -} diff --git a/transports/noise/src/protocol.rs b/transports/noise/src/protocol.rs index b947f16498b..6fa95dc3624 100644 --- a/transports/noise/src/protocol.rs +++ b/transports/noise/src/protocol.rs @@ -34,9 +34,56 @@ use zeroize::Zeroize; pub struct ProtocolParams(snow::params::NoiseParams); impl ProtocolParams { - /// Turn the protocol parameters into a session builder. - pub(crate) fn into_builder(self) -> snow::Builder<'static> { - snow::Builder::with_resolver(self.0, Box::new(Resolver)) + pub(crate) fn into_responder( + self, + prologue: &[u8], + private_key: &SecretKey, + remote_public_key: Option<&PublicKey>, + ) -> Result + where + C: Zeroize + AsRef<[u8]> + Protocol, + { + let state = self + .into_builder(prologue, private_key, remote_public_key) + .build_responder()?; + + Ok(state) + } + + pub(crate) fn into_initiator( + self, + prologue: &[u8], + private_key: &SecretKey, + remote_public_key: Option<&PublicKey>, + ) -> Result + where + C: Zeroize + AsRef<[u8]> + Protocol, + { + let state = self + .into_builder(prologue, private_key, remote_public_key) + .build_initiator()?; + + Ok(state) + } + + fn into_builder<'b, C>( + self, + prologue: &'b [u8], + private_key: &'b SecretKey, + remote_public_key: Option<&'b PublicKey>, + ) -> snow::Builder<'b> + where + C: Zeroize + AsRef<[u8]> + Protocol, + { + let mut builder = snow::Builder::with_resolver(self.0, Box::new(Resolver)) + .prologue(prologue.as_ref()) + .local_private_key(private_key.as_ref()); + + if let Some(remote_public_key) = remote_public_key { + builder = builder.remote_public_key(remote_public_key.as_ref()); + } + + builder } } @@ -284,3 +331,40 @@ impl rand::RngCore for Rng { impl rand::CryptoRng for Rng {} impl snow::types::Random for Rng {} + +#[cfg(test)] +mod tests { + use super::*; + use crate::X25519; + + #[test] + fn handshake_hashes_disagree_if_prologue_differs() { + let alice = xx_builder(b"alice prologue").build_initiator().unwrap(); + let bob = xx_builder(b"bob prologue").build_responder().unwrap(); + + let alice_handshake_hash = alice.get_handshake_hash(); + let bob_handshake_hash = bob.get_handshake_hash(); + + assert_ne!(alice_handshake_hash, bob_handshake_hash) + } + + #[test] + fn handshake_hashes_agree_if_prologue_is_the_same() { + let alice = xx_builder(b"shared knowledge").build_initiator().unwrap(); + let bob = xx_builder(b"shared knowledge").build_responder().unwrap(); + + let alice_handshake_hash = alice.get_handshake_hash(); + let bob_handshake_hash = bob.get_handshake_hash(); + + assert_eq!(alice_handshake_hash, bob_handshake_hash) + } + + fn xx_builder(prologue: &'static [u8]) -> snow::Builder<'static> { + X25519::params_xx().into_builder(prologue, &TEST_KEY.secret(), None) + } + + // Hack to work around borrow-checker. + lazy_static::lazy_static! { + static ref TEST_KEY: Keypair = Keypair::::new(); + } +} From fa6ad2b3d633f2423cbd1db27f37a8e7e498108c Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Fri, 30 Sep 2022 16:54:17 +1000 Subject: [PATCH 15/23] Apply suggestions from code review --- transports/noise/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 8be39693068..aa6bd774b36 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -273,7 +273,7 @@ where /// /// `XX` is a 1.5 round-trip (3 messages) handshake. /// The first message in a noise handshake is unencrypted. In the `XX` handshake pattern, that message -/// is empty and thus does not leak and information. The identities are then exchanged in the second +/// is empty and thus does not leak any information. The identities are then exchanged in the second /// and third message. /// /// ```raw @@ -319,7 +319,7 @@ where /// /// `XX` is a 1.5 round-trip (3 messages) handshake. /// The first message in a noise handshake is unencrypted. In the `XX` handshake pattern, that message -/// is empty and thus does not leak and information. The identities are then exchanged in the second +/// is empty and thus does not leak any information. The identities are then exchanged in the second /// and third message. /// /// ```raw From 49835a71ca258eb29a6d9cc7bba7b4900caed285 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 4 Oct 2022 15:25:40 +1100 Subject: [PATCH 16/23] Fix bad roles in noise handshake --- transports/noise/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 8be39693068..4084fbbacb9 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -248,7 +248,7 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_responder( + let session = self.params.into_initiator( &self.prologue, self.dh_keys.dh_keypair().secret(), None, @@ -339,7 +339,7 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_responder( + let session = self.params.into_initiator( &self.prologue, self.dh_keys.dh_keypair().secret(), None, From 020642aa9f194032c57fe49c817e89606cafbae8 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 4 Oct 2022 15:28:43 +1100 Subject: [PATCH 17/23] Don't import `BoxFuture` through imported module --- transports/noise/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 968dedf5980..27050214459 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -64,9 +64,9 @@ pub use protocol::{x25519::X25519, x25519_spec::X25519Spec}; pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey}; pub use protocol::{Protocol, ProtocolParams, IK, IX, XX}; -use crate::future::BoxFuture; use crate::handshake::State; use crate::io::handshake; +use futures::future::BoxFuture; use futures::prelude::*; use libp2p_core::{identity, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo}; use std::pin::Pin; From b2e9df551fd30683b3698c463c7fe68667ead1b5 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 4 Oct 2022 15:50:10 +1100 Subject: [PATCH 18/23] Move traits to where clause --- transports/noise/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 27050214459..4d4c9d63201 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -90,7 +90,10 @@ pub struct NoiseConfig { prologue: Vec, } -impl NoiseConfig { +impl NoiseConfig +where + C: Zeroize, +{ /// Turn the `NoiseConfig` into an authenticated upgrade for use /// with a `Swarm`. pub fn into_authenticated(self) -> NoiseAuthenticated { From 099c9855ff86b6f41fb9330f79fe5e77783ecba0 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 4 Oct 2022 15:57:38 +1100 Subject: [PATCH 19/23] Move `into_initiator` and `into_responder` back to `NoiseConfig` --- transports/noise/CHANGELOG.md | 1 + transports/noise/src/lib.rs | 150 +++++++++++++++---------------- transports/noise/src/protocol.rs | 42 ++------- 3 files changed, 79 insertions(+), 114 deletions(-) diff --git a/transports/noise/CHANGELOG.md b/transports/noise/CHANGELOG.md index 78b0d3d5507..6c7b94c5876 100644 --- a/transports/noise/CHANGELOG.md +++ b/transports/noise/CHANGELOG.md @@ -7,6 +7,7 @@ - Add `NoiseConfig::with_prologue` which allows users to set the noise prologue of the handshake. See [PR 2903]. - Remove `Deref` implementation on `AuthenticKeypair`. See [PR 2909]. - Make `handshake` module private. See [PR 2909]. +- Deprecate `AuthenticKeypair::into_identity`. See [PR 2909]. [PR 2887]: https://github.com/libp2p/rust-libp2p/pull/2887 [PR 2903]: https://github.com/libp2p/rust-libp2p/pull/2903 diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 4d4c9d63201..aa808f0623b 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -112,6 +112,36 @@ where } } +/// Implement `into_responder` and `into_initiator` for all configs where R = (). +/// +/// This allows us to ignore the `remote` field. +impl NoiseConfig +where + C: Zeroize + Protocol + AsRef<[u8]>, +{ + fn into_responder(self, socket: S) -> Result, NoiseError> { + let session = self + .params + .into_builder(&self.prologue, self.dh_keys.keypair.secret(), None) + .build_responder()?; + + let state = State::new(socket, session, self.dh_keys.identity, None, self.legacy); + + Ok(state) + } + + fn into_initiator(self, socket: S) -> Result, NoiseError> { + let session = self + .params + .into_builder(&self.prologue, self.dh_keys.keypair.secret(), None) + .build_initiator()?; + + let state = State::new(socket, session, self.dh_keys.identity, None, self.legacy); + + Ok(state) + } +} + impl NoiseConfig where C: Protocol + Zeroize, @@ -168,7 +198,7 @@ where impl NoiseConfig, identity::PublicKey)> where - C: Protocol + Zeroize, + C: Protocol + Zeroize + AsRef<[u8]>, { /// Create a new `NoiseConfig` for the `IK` handshake pattern (initiator side). /// @@ -188,6 +218,28 @@ where prologue: Vec::default(), } } + + /// Specialised implementation of `into_initiator` for the `IK` handshake where `R != ()`. + fn into_initiator(self, socket: S) -> Result, NoiseError> { + let session = self + .params + .into_builder( + &self.prologue, + self.dh_keys.keypair.secret(), + Some(&self.remote.0), + ) + .build_initiator()?; + + let state = State::new( + socket, + session, + self.dh_keys.identity, + Some(self.remote.1), + self.legacy, + ); + + Ok(state) + } } /// Implements the responder part of the `IX` noise handshake pattern. @@ -210,21 +262,11 @@ where fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_responder( - &self.prologue, - self.dh_keys.dh_keypair().secret(), - None, - )?; - - let mut state = State::new( - socket, - session, - self.dh_keys.into_identity(), - None, - self.legacy, - ); + let mut state = self.into_responder(socket)?; + handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; + state.finish() } .boxed() @@ -251,21 +293,11 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_initiator( - &self.prologue, - self.dh_keys.dh_keypair().secret(), - None, - )?; - - let mut state = State::new( - socket, - session, - self.dh_keys.into_identity(), - None, - self.legacy, - ); + let mut state = self.into_initiator(socket)?; + handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; + state.finish() } .boxed() @@ -296,22 +328,12 @@ where fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_responder( - &self.prologue, - self.dh_keys.dh_keypair().secret(), - None, - )?; - - let mut state = State::new( - socket, - session, - self.dh_keys.into_identity(), - None, - self.legacy, - ); + let mut state = self.into_responder(socket)?; + handshake::recv_empty(&mut state).await?; handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; + state.finish() } .boxed() @@ -342,22 +364,12 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_initiator( - &self.prologue, - self.dh_keys.dh_keypair().secret(), - None, - )?; - - let mut state = State::new( - socket, - session, - self.dh_keys.into_identity(), - None, - self.legacy, - ); + let mut state = self.into_initiator(socket)?; + handshake::send_empty(&mut state).await?; handshake::recv_identity(&mut state).await?; handshake::send_identity(&mut state).await?; + state.finish() } .boxed() @@ -387,21 +399,11 @@ where fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_responder( - &self.prologue, - self.dh_keys.dh_keypair().secret(), - None, - )?; - - let mut state = State::new( - socket, - session, - self.dh_keys.into_identity(), - None, - self.legacy, - ); + let mut state = self.into_responder(socket)?; + handshake::recv_identity(&mut state).await?; handshake::send_signature_only(&mut state).await?; + state.finish() } .boxed() @@ -431,21 +433,11 @@ where fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future { async move { - let session = self.params.into_initiator( - &self.prologue, - self.dh_keys.dh_keypair().secret(), - Some(&self.remote.0), - )?; - - let mut state = State::new( - socket, - session, - self.dh_keys.into_identity(), - Some(self.remote.1), - self.legacy, - ); + let mut state = self.into_initiator(socket)?; + handshake::send_identity(&mut state).await?; handshake::recv_identity(&mut state).await?; + state.finish() } .boxed() diff --git a/transports/noise/src/protocol.rs b/transports/noise/src/protocol.rs index 6fa95dc3624..70cdc43d662 100644 --- a/transports/noise/src/protocol.rs +++ b/transports/noise/src/protocol.rs @@ -34,39 +34,7 @@ use zeroize::Zeroize; pub struct ProtocolParams(snow::params::NoiseParams); impl ProtocolParams { - pub(crate) fn into_responder( - self, - prologue: &[u8], - private_key: &SecretKey, - remote_public_key: Option<&PublicKey>, - ) -> Result - where - C: Zeroize + AsRef<[u8]> + Protocol, - { - let state = self - .into_builder(prologue, private_key, remote_public_key) - .build_responder()?; - - Ok(state) - } - - pub(crate) fn into_initiator( - self, - prologue: &[u8], - private_key: &SecretKey, - remote_public_key: Option<&PublicKey>, - ) -> Result - where - C: Zeroize + AsRef<[u8]> + Protocol, - { - let state = self - .into_builder(prologue, private_key, remote_public_key) - .build_initiator()?; - - Ok(state) - } - - fn into_builder<'b, C>( + pub(crate) fn into_builder<'b, C>( self, prologue: &'b [u8], private_key: &'b SecretKey, @@ -165,8 +133,8 @@ pub struct Keypair { /// A DH keypair that is authentic w.r.t. a [`identity::PublicKey`]. #[derive(Clone)] pub struct AuthenticKeypair { - keypair: Keypair, - identity: KeypairIdentity, + pub(crate) keypair: Keypair, + pub(crate) identity: KeypairIdentity, } impl AuthenticKeypair { @@ -176,6 +144,10 @@ impl AuthenticKeypair { /// Extract the public [`KeypairIdentity`] from this `AuthenticKeypair`, /// dropping the DH `Keypair`. + #[deprecated( + since = "0.40.0", + note = "This function was only used internally and will be removed in the future unless more usecases come up." + )] pub fn into_identity(self) -> KeypairIdentity { self.identity } From 1a65ac7a6e01ba4766927443daa903171a566843 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 4 Oct 2022 15:58:37 +1100 Subject: [PATCH 20/23] Revert "Move traits to where clause" This reverts commit b2e9df551fd30683b3698c463c7fe68667ead1b5. --- transports/noise/src/lib.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index aa808f0623b..72f3c5568c3 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -90,10 +90,7 @@ pub struct NoiseConfig { prologue: Vec, } -impl NoiseConfig -where - C: Zeroize, -{ +impl NoiseConfig { /// Turn the `NoiseConfig` into an authenticated upgrade for use /// with a `Swarm`. pub fn into_authenticated(self) -> NoiseAuthenticated { From ee4816310272b9b3458430ba0928cd6b64d9147a Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 4 Oct 2022 15:59:51 +1100 Subject: [PATCH 21/23] Use backticks in docs --- transports/noise/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transports/noise/src/lib.rs b/transports/noise/src/lib.rs index 72f3c5568c3..ac341c2802d 100644 --- a/transports/noise/src/lib.rs +++ b/transports/noise/src/lib.rs @@ -109,7 +109,7 @@ impl NoiseConfig { } } -/// Implement `into_responder` and `into_initiator` for all configs where R = (). +/// Implement `into_responder` and `into_initiator` for all configs where `R = ()`. /// /// This allows us to ignore the `remote` field. impl NoiseConfig From b5cdfcb38ad3665e0234b0b60214da0d846777d3 Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 4 Oct 2022 16:00:58 +1100 Subject: [PATCH 22/23] Don't expose entire DH keypair --- transports/noise/src/protocol.rs | 5 +++-- transports/noise/tests/smoke.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/transports/noise/src/protocol.rs b/transports/noise/src/protocol.rs index 70cdc43d662..9e9f430cc10 100644 --- a/transports/noise/src/protocol.rs +++ b/transports/noise/src/protocol.rs @@ -138,8 +138,9 @@ pub struct AuthenticKeypair { } impl AuthenticKeypair { - pub fn dh_keypair(&self) -> &Keypair { - &self.keypair + /// Returns the public DH key of this keypair. + pub fn public_dh_key(&self) -> &PublicKey { + &self.keypair.public } /// Extract the public [`KeypairIdentity`] from this `AuthenticKeypair`, diff --git a/transports/noise/tests/smoke.rs b/transports/noise/tests/smoke.rs index f4d3fff85e6..c69ebe03132 100644 --- a/transports/noise/tests/smoke.rs +++ b/transports/noise/tests/smoke.rs @@ -197,7 +197,7 @@ fn ik_xx() { let client_id_public = client_id.public(); let server_dh = Keypair::::new().into_authentic(&server_id).unwrap(); - let server_dh_public = server_dh.dh_keypair().public().clone(); + let server_dh_public = server_dh.public_dh_key().clone(); let server_transport = TcpTransport::default() .and_then(move |output, endpoint| { if endpoint.is_listener() { From 79f3983c9eb4dd1b15154f76b79038d4d396e6ab Mon Sep 17 00:00:00 2001 From: Thomas Eizinger Date: Tue, 11 Oct 2022 22:03:40 +1100 Subject: [PATCH 23/23] Fix clippy error --- transports/noise/src/protocol.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transports/noise/src/protocol.rs b/transports/noise/src/protocol.rs index 9e9f430cc10..9b57f05d0ba 100644 --- a/transports/noise/src/protocol.rs +++ b/transports/noise/src/protocol.rs @@ -333,7 +333,7 @@ mod tests { } fn xx_builder(prologue: &'static [u8]) -> snow::Builder<'static> { - X25519::params_xx().into_builder(prologue, &TEST_KEY.secret(), None) + X25519::params_xx().into_builder(prologue, TEST_KEY.secret(), None) } // Hack to work around borrow-checker.