Skip to content

Commit

Permalink
protocols/noise: Add NoiseConfig::with_prologue (#2903)
Browse files Browse the repository at this point in the history
  • Loading branch information
thomaseizinger committed Sep 21, 2022
1 parent 39d6351 commit ed1b899
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 52 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
# 0.49.0 - [unreleased]

- Update to [`libp2p-tcp` `v0.37.0`](transports/tcp/CHANGELOG.md#0370).
-
- Update to [`libp2p-noise` `v0.39.1`](transports/noise/CHANGELOG.md#0391).

- Update to [`libp2p-swarm-derive` `v0.30.1`](swarm-derive/CHANGELOG.md#0301).

Expand Down
2 changes: 2 additions & 0 deletions transports/noise/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

- 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].
- Add `NoiseConfig::with_prologue` which allows users to set the noise prologue of the handshake. See [PR 2903].

[PR 2887]: https://github.com/libp2p/rust-libp2p/pull/2887
[PR 2903]: https://github.com/libp2p/rust-libp2p/pull/2903

# 0.39.0

Expand Down
186 changes: 134 additions & 52 deletions transports/noise/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ pub use protocol::{Protocol, ProtocolParams, IK, IX, XX};

use futures::prelude::*;
use libp2p_core::{identity, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo};
use snow::HandshakeState;
use std::pin::Pin;
use zeroize::Zeroize;

Expand All @@ -78,6 +79,14 @@ pub struct NoiseConfig<P, C: Zeroize, R = ()> {
legacy: LegacyConfig,
remote: R,
_marker: std::marker::PhantomData<P>,

/// Prologue to use in the noise handshake.
///
/// The prologue can contain arbitrary data that will be hashed into the noise handshake.
/// For the handshake to succeed, both parties must set the same prologue.
///
/// For further information, see <https://noiseprotocol.org/noise.html#prologue>.
prologue: Vec<u8>,
}

impl<H, C: Zeroize, R> NoiseConfig<H, C, R> {
Expand All @@ -87,13 +96,47 @@ impl<H, C: Zeroize, R> NoiseConfig<H, C, R> {
NoiseAuthenticated { config: self }
}

/// Set the noise prologue.
pub fn with_prologue(self, prologue: Vec<u8>) -> Self {
Self { prologue, ..self }
}

/// Sets the legacy configuration options to use, if any.
pub fn set_legacy_config(&mut self, cfg: LegacyConfig) -> &mut Self {
self.legacy = cfg;
self
}
}

impl<H, C, R> NoiseConfig<H, C, R>
where
C: Zeroize + AsRef<[u8]>,
{
fn into_responder(self) -> Result<HandshakeState, NoiseError> {
let state = self
.params
.into_builder()
.prologue(self.prologue.as_ref())
.local_private_key(self.dh_keys.secret().as_ref())
.build_responder()
.map_err(NoiseError::from)?;

Ok(state)
}

fn into_initiator(self) -> Result<HandshakeState, NoiseError> {
let state = self
.params
.into_builder()
.prologue(self.prologue.as_ref())
.local_private_key(self.dh_keys.secret().as_ref())
.build_initiator()
.map_err(NoiseError::from)?;

Ok(state)
}
}

impl<C> NoiseConfig<IX, C>
where
C: Protocol<C> + Zeroize,
Expand All @@ -106,6 +149,7 @@ where
legacy: LegacyConfig::default(),
remote: (),
_marker: std::marker::PhantomData,
prologue: Vec::default(),
}
}
}
Expand All @@ -122,6 +166,7 @@ where
legacy: LegacyConfig::default(),
remote: (),
_marker: std::marker::PhantomData,
prologue: Vec::default(),
}
}
}
Expand All @@ -141,6 +186,7 @@ where
legacy: LegacyConfig::default(),
remote: (),
_marker: std::marker::PhantomData,
prologue: Vec::default(),
}
}
}
Expand All @@ -164,6 +210,7 @@ where
legacy: LegacyConfig::default(),
remote: (remote_dh, remote_id),
_marker: std::marker::PhantomData,
prologue: Vec::default(),
}
}
}
Expand All @@ -174,25 +221,22 @@ impl<T, C> InboundUpgrade<T> for NoiseConfig<IX, C>
where
NoiseConfig<IX, C>: UpgradeInfo,
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
{
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
type Error = NoiseError;
type Future = Handshake<T, C>;

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);
let config = self.legacy;
let identity = self.dh_keys.clone().into_identity();

handshake::rt1_responder(
socket,
session,
self.dh_keys.into_identity(),
self.into_responder(),
identity,
IdentityExchange::Mutual,
self.legacy,
config,
)
}
}
Expand All @@ -201,25 +245,22 @@ impl<T, C> OutboundUpgrade<T> for NoiseConfig<IX, C>
where
NoiseConfig<IX, C>: UpgradeInfo,
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
{
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
type Error = NoiseError;
type Future = Handshake<T, C>;

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);
let legacy = self.legacy;
let identity = self.dh_keys.clone().into_identity();

handshake::rt1_initiator(
socket,
session,
self.dh_keys.into_identity(),
self.into_initiator(),
identity,
IdentityExchange::Mutual,
self.legacy,
legacy,
)
}
}
Expand All @@ -230,25 +271,22 @@ impl<T, C> InboundUpgrade<T> for NoiseConfig<XX, C>
where
NoiseConfig<XX, C>: UpgradeInfo,
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
{
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
type Error = NoiseError;
type Future = Handshake<T, C>;

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);
let legacy = self.legacy;
let identity = self.dh_keys.clone().into_identity();

handshake::rt15_responder(
socket,
session,
self.dh_keys.into_identity(),
self.into_responder(),
identity,
IdentityExchange::Mutual,
self.legacy,
legacy,
)
}
}
Expand All @@ -257,25 +295,22 @@ impl<T, C> OutboundUpgrade<T> for NoiseConfig<XX, C>
where
NoiseConfig<XX, C>: UpgradeInfo,
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
{
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
type Error = NoiseError;
type Future = Handshake<T, C>;

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);
let legacy = self.legacy;
let identity = self.dh_keys.clone().into_identity();

handshake::rt15_initiator(
socket,
session,
self.dh_keys.into_identity(),
self.into_initiator(),
identity,
IdentityExchange::Mutual,
self.legacy,
legacy,
)
}
}
Expand All @@ -286,25 +321,22 @@ impl<T, C, R> InboundUpgrade<T> for NoiseConfig<IK, C, R>
where
NoiseConfig<IK, C, R>: UpgradeInfo,
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
{
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
type Error = NoiseError;
type Future = Handshake<T, C>;

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);
let legacy = self.legacy;
let identity = self.dh_keys.clone().into_identity();

handshake::rt1_responder(
socket,
session,
self.dh_keys.into_identity(),
self.into_responder(),
identity,
IdentityExchange::Receive,
self.legacy,
legacy,
)
}
}
Expand All @@ -313,7 +345,7 @@ impl<T, C> OutboundUpgrade<T> for NoiseConfig<IK, C, (PublicKey<C>, identity::Pu
where
NoiseConfig<IK, C, (PublicKey<C>, identity::PublicKey)>: UpgradeInfo,
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Send + 'static,
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
{
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
type Error = NoiseError;
Expand All @@ -323,10 +355,12 @@ where
let session = self
.params
.into_builder()
.prologue(self.prologue.as_ref())
.local_private_key(self.dh_keys.secret().as_ref())
.remote_public_key(self.remote.0.as_ref())
.build_initiator()
.map_err(NoiseError::from);

handshake::rt1_initiator(
socket,
session,
Expand Down Expand Up @@ -432,7 +466,7 @@ where
}

/// Legacy configuration options.
#[derive(Clone, Default)]
#[derive(Clone, Copy, Default)]
pub struct LegacyConfig {
/// Whether to continue sending legacy handshake payloads,
/// i.e. length-prefixed protobuf payloads inside a length-prefixed
Expand All @@ -445,3 +479,51 @@ 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<XX, X25519> {
let dh_keys = Keypair::<X25519>::new();
let noise_keys = dh_keys
.into_authentic(&identity::Keypair::generate_ed25519())
.unwrap();

NoiseConfig::xx(noise_keys)
}
}

0 comments on commit ed1b899

Please sign in to comment.