mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-03 05:01:24 +00:00
protocols/noise: Inline handshake
functions into upgrade traits (#2909)
- Remove `Deref` implementation on `AuthenticKeypair`. - Make `handshake` module private. - Deprecate `AuthenticKeypair::into_identity`.
This commit is contained in:
parent
31a45f2d76
commit
eba2efe29a
@ -5,9 +5,13 @@
|
|||||||
- Introduce `NoiseAuthenticated::xx` constructor, assuming a X25519 DH key exchange. An XX key exchange and X25519 keys
|
- 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].
|
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].
|
- 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 2887]: https://github.com/libp2p/rust-libp2p/pull/2887
|
||||||
[PR 2903]: https://github.com/libp2p/rust-libp2p/pull/2903
|
[PR 2903]: https://github.com/libp2p/rust-libp2p/pull/2903
|
||||||
|
[PR 2909]: https://github.com/libp2p/rust-libp2p/pull/2909
|
||||||
|
|
||||||
# 0.39.0
|
# 0.39.0
|
||||||
|
|
||||||
|
@ -31,10 +31,9 @@ use crate::protocol::{KeypairIdentity, Protocol, PublicKey};
|
|||||||
use crate::LegacyConfig;
|
use crate::LegacyConfig;
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use futures::task;
|
|
||||||
use libp2p_core::identity;
|
use libp2p_core::identity;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use std::{io, pin::Pin, task::Context};
|
use std::io;
|
||||||
|
|
||||||
/// The identity of the remote established during a handshake.
|
/// The identity of the remote established during a handshake.
|
||||||
pub enum RemoteIdentity<C> {
|
pub enum RemoteIdentity<C> {
|
||||||
@ -63,199 +62,11 @@ pub enum RemoteIdentity<C> {
|
|||||||
IdentityKey(identity::PublicKey),
|
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 },
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A future performing a Noise handshake pattern.
|
|
||||||
pub struct Handshake<T, C>(
|
|
||||||
Pin<Box<dyn Future<Output = Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>> + Send>>,
|
|
||||||
);
|
|
||||||
|
|
||||||
impl<T, C> Future for Handshake<T, C> {
|
|
||||||
type Output = Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>;
|
|
||||||
|
|
||||||
fn poll(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> task::Poll<Self::Output> {
|
|
||||||
Pin::new(&mut self.0).poll(ctx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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<T, C>(
|
|
||||||
io: T,
|
|
||||||
session: Result<snow::HandshakeState, NoiseError>,
|
|
||||||
identity: KeypairIdentity,
|
|
||||||
identity_x: IdentityExchange,
|
|
||||||
legacy: LegacyConfig,
|
|
||||||
) -> Handshake<T, C>
|
|
||||||
where
|
|
||||||
T: AsyncWrite + AsyncRead + Send + Unpin + 'static,
|
|
||||||
C: Protocol<C> + 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<T, C>(
|
|
||||||
io: T,
|
|
||||||
session: Result<snow::HandshakeState, NoiseError>,
|
|
||||||
identity: KeypairIdentity,
|
|
||||||
identity_x: IdentityExchange,
|
|
||||||
legacy: LegacyConfig,
|
|
||||||
) -> Handshake<T, C>
|
|
||||||
where
|
|
||||||
T: AsyncWrite + AsyncRead + Send + Unpin + 'static,
|
|
||||||
C: Protocol<C> + 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<T, C>(
|
|
||||||
io: T,
|
|
||||||
session: Result<snow::HandshakeState, NoiseError>,
|
|
||||||
identity: KeypairIdentity,
|
|
||||||
identity_x: IdentityExchange,
|
|
||||||
legacy: LegacyConfig,
|
|
||||||
) -> Handshake<T, C>
|
|
||||||
where
|
|
||||||
T: AsyncWrite + AsyncRead + Unpin + Send + 'static,
|
|
||||||
C: Protocol<C> + 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<T, C>(
|
|
||||||
io: T,
|
|
||||||
session: Result<snow::HandshakeState, NoiseError>,
|
|
||||||
identity: KeypairIdentity,
|
|
||||||
identity_x: IdentityExchange,
|
|
||||||
legacy: LegacyConfig,
|
|
||||||
) -> Handshake<T, C>
|
|
||||||
where
|
|
||||||
T: AsyncWrite + AsyncRead + Unpin + Send + 'static,
|
|
||||||
C: Protocol<C> + 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
|
// Internal
|
||||||
|
|
||||||
/// Handshake state.
|
/// Handshake state.
|
||||||
struct State<T> {
|
pub struct State<T> {
|
||||||
/// The underlying I/O resource.
|
/// The underlying I/O resource.
|
||||||
io: NoiseFramed<T, snow::HandshakeState>,
|
io: NoiseFramed<T, snow::HandshakeState>,
|
||||||
/// The associated public identity of the local node's static DH keypair,
|
/// The associated public identity of the local node's static DH keypair,
|
||||||
@ -265,8 +76,6 @@ struct State<T> {
|
|||||||
dh_remote_pubkey_sig: Option<Vec<u8>>,
|
dh_remote_pubkey_sig: Option<Vec<u8>>,
|
||||||
/// The known or received public identity key of the remote, if any.
|
/// The known or received public identity key of the remote, if any.
|
||||||
id_remote_pubkey: Option<identity::PublicKey>,
|
id_remote_pubkey: Option<identity::PublicKey>,
|
||||||
/// Whether to send the public identity key of the local node to the remote.
|
|
||||||
send_identity: bool,
|
|
||||||
/// Legacy configuration parameters.
|
/// Legacy configuration parameters.
|
||||||
legacy: LegacyConfig,
|
legacy: LegacyConfig,
|
||||||
}
|
}
|
||||||
@ -277,34 +86,27 @@ impl<T> State<T> {
|
|||||||
/// will be sent and received on the given I/O resource and using the
|
/// will be sent and received on the given I/O resource and using the
|
||||||
/// provided session for cryptographic operations according to the chosen
|
/// provided session for cryptographic operations according to the chosen
|
||||||
/// Noise handshake pattern.
|
/// Noise handshake pattern.
|
||||||
fn new(
|
pub fn new(
|
||||||
io: T,
|
io: T,
|
||||||
session: Result<snow::HandshakeState, NoiseError>,
|
session: snow::HandshakeState,
|
||||||
identity: KeypairIdentity,
|
identity: KeypairIdentity,
|
||||||
identity_x: IdentityExchange,
|
expected_remote_key: Option<identity::PublicKey>,
|
||||||
legacy: LegacyConfig,
|
legacy: LegacyConfig,
|
||||||
) -> Result<Self, NoiseError> {
|
) -> Self {
|
||||||
let (id_remote_pubkey, send_identity) = match identity_x {
|
Self {
|
||||||
IdentityExchange::Mutual => (None, true),
|
|
||||||
IdentityExchange::Send { remote } => (Some(remote), true),
|
|
||||||
IdentityExchange::Receive => (None, false),
|
|
||||||
IdentityExchange::None { remote } => (Some(remote), false),
|
|
||||||
};
|
|
||||||
session.map(|s| State {
|
|
||||||
identity,
|
identity,
|
||||||
io: NoiseFramed::new(io, s),
|
io: NoiseFramed::new(io, session),
|
||||||
dh_remote_pubkey_sig: None,
|
dh_remote_pubkey_sig: None,
|
||||||
id_remote_pubkey,
|
id_remote_pubkey: expected_remote_key,
|
||||||
send_identity,
|
|
||||||
legacy,
|
legacy,
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> State<T> {
|
impl<T> State<T> {
|
||||||
/// Finish a handshake, yielding the established remote identity and the
|
/// Finish a handshake, yielding the established remote identity and the
|
||||||
/// [`NoiseOutput`] for communicating on the encrypted channel.
|
/// [`NoiseOutput`] for communicating on the encrypted channel.
|
||||||
fn finish<C>(self) -> Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>
|
pub fn finish<C>(self) -> Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>
|
||||||
where
|
where
|
||||||
C: Protocol<C> + AsRef<[u8]>,
|
C: Protocol<C> + AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
@ -340,7 +142,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A future for receiving a Noise handshake message with an empty payload.
|
/// A future for receiving a Noise handshake message with an empty payload.
|
||||||
async fn recv_empty<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
pub async fn recv_empty<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
||||||
where
|
where
|
||||||
T: AsyncRead + Unpin,
|
T: AsyncRead + Unpin,
|
||||||
{
|
{
|
||||||
@ -354,7 +156,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A future for sending a Noise handshake message with an empty payload.
|
/// A future for sending a Noise handshake message with an empty payload.
|
||||||
async fn send_empty<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
pub async fn send_empty<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
||||||
where
|
where
|
||||||
T: AsyncWrite + Unpin,
|
T: AsyncWrite + Unpin,
|
||||||
{
|
{
|
||||||
@ -364,7 +166,10 @@ where
|
|||||||
|
|
||||||
/// A future for receiving a Noise handshake message with a payload
|
/// A future for receiving a Noise handshake message with a payload
|
||||||
/// identifying the remote.
|
/// identifying the remote.
|
||||||
async fn recv_identity<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
///
|
||||||
|
/// 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<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
||||||
where
|
where
|
||||||
T: AsyncRead + Unpin,
|
T: AsyncRead + Unpin,
|
||||||
{
|
{
|
||||||
@ -421,15 +226,40 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Send a Noise handshake message with a payload identifying the local node to the remote.
|
/// Send a Noise handshake message with a payload identifying the local node to the remote.
|
||||||
async fn send_identity<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
pub async fn send_identity<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
||||||
where
|
where
|
||||||
T: AsyncWrite + Unpin,
|
T: AsyncWrite + Unpin,
|
||||||
{
|
{
|
||||||
let mut pb = payload_proto::NoiseHandshakePayload::default();
|
let mut pb = payload_proto::NoiseHandshakePayload {
|
||||||
|
identity_key: state.identity.public.to_protobuf_encoding(),
|
||||||
if state.send_identity {
|
..Default::default()
|
||||||
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<u8> 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<T>(state: &mut State<T>) -> Result<(), NoiseError>
|
||||||
|
where
|
||||||
|
T: AsyncWrite + Unpin,
|
||||||
|
{
|
||||||
|
let mut pb = payload_proto::NoiseHandshakePayload::default();
|
||||||
|
|
||||||
if let Some(ref sig) = state.identity.signature {
|
if let Some(ref sig) = state.identity.signature {
|
||||||
pb.identity_sig = sig.clone()
|
pb.identity_sig = sig.clone()
|
||||||
|
@ -58,16 +58,17 @@ mod io;
|
|||||||
mod protocol;
|
mod protocol;
|
||||||
|
|
||||||
pub use error::NoiseError;
|
pub use error::NoiseError;
|
||||||
pub use io::handshake;
|
pub use io::handshake::RemoteIdentity;
|
||||||
pub use io::handshake::{Handshake, IdentityExchange, RemoteIdentity};
|
|
||||||
pub use io::NoiseOutput;
|
pub use io::NoiseOutput;
|
||||||
pub use protocol::{x25519::X25519, x25519_spec::X25519Spec};
|
pub use protocol::{x25519::X25519, x25519_spec::X25519Spec};
|
||||||
pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey};
|
pub use protocol::{AuthenticKeypair, Keypair, KeypairIdentity, PublicKey, SecretKey};
|
||||||
pub use protocol::{Protocol, ProtocolParams, IK, IX, XX};
|
pub use protocol::{Protocol, ProtocolParams, IK, IX, XX};
|
||||||
|
|
||||||
|
use crate::handshake::State;
|
||||||
|
use crate::io::handshake;
|
||||||
|
use futures::future::BoxFuture;
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use libp2p_core::{identity, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo};
|
use libp2p_core::{identity, InboundUpgrade, OutboundUpgrade, PeerId, UpgradeInfo};
|
||||||
use snow::HandshakeState;
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
@ -108,30 +109,31 @@ impl<H, C: Zeroize, R> NoiseConfig<H, C, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, C, R> NoiseConfig<H, C, R>
|
/// Implement `into_responder` and `into_initiator` for all configs where `R = ()`.
|
||||||
|
///
|
||||||
|
/// This allows us to ignore the `remote` field.
|
||||||
|
impl<H, C> NoiseConfig<H, C, ()>
|
||||||
where
|
where
|
||||||
C: Zeroize + AsRef<[u8]>,
|
C: Zeroize + Protocol<C> + AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
fn into_responder(self) -> Result<HandshakeState, NoiseError> {
|
fn into_responder<S>(self, socket: S) -> Result<State<S>, NoiseError> {
|
||||||
let state = self
|
let session = self
|
||||||
.params
|
.params
|
||||||
.into_builder()
|
.into_builder(&self.prologue, self.dh_keys.keypair.secret(), None)
|
||||||
.prologue(self.prologue.as_ref())
|
.build_responder()?;
|
||||||
.local_private_key(self.dh_keys.secret().as_ref())
|
|
||||||
.build_responder()
|
let state = State::new(socket, session, self.dh_keys.identity, None, self.legacy);
|
||||||
.map_err(NoiseError::from)?;
|
|
||||||
|
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_initiator(self) -> Result<HandshakeState, NoiseError> {
|
fn into_initiator<S>(self, socket: S) -> Result<State<S>, NoiseError> {
|
||||||
let state = self
|
let session = self
|
||||||
.params
|
.params
|
||||||
.into_builder()
|
.into_builder(&self.prologue, self.dh_keys.keypair.secret(), None)
|
||||||
.prologue(self.prologue.as_ref())
|
.build_initiator()?;
|
||||||
.local_private_key(self.dh_keys.secret().as_ref())
|
|
||||||
.build_initiator()
|
let state = State::new(socket, session, self.dh_keys.identity, None, self.legacy);
|
||||||
.map_err(NoiseError::from)?;
|
|
||||||
|
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
@ -193,7 +195,7 @@ where
|
|||||||
|
|
||||||
impl<C> NoiseConfig<IK, C, (PublicKey<C>, identity::PublicKey)>
|
impl<C> NoiseConfig<IK, C, (PublicKey<C>, identity::PublicKey)>
|
||||||
where
|
where
|
||||||
C: Protocol<C> + Zeroize,
|
C: Protocol<C> + Zeroize + AsRef<[u8]>,
|
||||||
{
|
{
|
||||||
/// Create a new `NoiseConfig` for the `IK` handshake pattern (initiator side).
|
/// Create a new `NoiseConfig` for the `IK` handshake pattern (initiator side).
|
||||||
///
|
///
|
||||||
@ -213,10 +215,38 @@ where
|
|||||||
prologue: Vec::default(),
|
prologue: Vec::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Specialised implementation of `into_initiator` for the `IK` handshake where `R != ()`.
|
||||||
|
fn into_initiator<S>(self, socket: S) -> Result<State<S>, 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handshake pattern IX /////////////////////////////////////////////////////
|
/// Implements the responder part of the `IX` noise handshake pattern.
|
||||||
|
///
|
||||||
|
/// `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
|
||||||
|
/// initiator <-{id}- responder
|
||||||
|
/// ```
|
||||||
impl<T, C> InboundUpgrade<T> for NoiseConfig<IX, C>
|
impl<T, C> InboundUpgrade<T> for NoiseConfig<IX, C>
|
||||||
where
|
where
|
||||||
NoiseConfig<IX, C>: UpgradeInfo,
|
NoiseConfig<IX, C>: UpgradeInfo,
|
||||||
@ -225,22 +255,29 @@ where
|
|||||||
{
|
{
|
||||||
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
||||||
type Error = NoiseError;
|
type Error = NoiseError;
|
||||||
type Future = Handshake<T, C>;
|
type Future = BoxFuture<'static, Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>>;
|
||||||
|
|
||||||
fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
|
fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
|
||||||
let config = self.legacy;
|
async move {
|
||||||
let identity = self.dh_keys.clone().into_identity();
|
let mut state = self.into_responder(socket)?;
|
||||||
|
|
||||||
handshake::rt1_responder(
|
handshake::recv_identity(&mut state).await?;
|
||||||
socket,
|
handshake::send_identity(&mut state).await?;
|
||||||
self.into_responder(),
|
|
||||||
identity,
|
state.finish()
|
||||||
IdentityExchange::Mutual,
|
}
|
||||||
config,
|
.boxed()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implements the initiator part of the `IX` noise handshake pattern.
|
||||||
|
///
|
||||||
|
/// `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
|
||||||
|
/// initiator <-{id}- responder
|
||||||
|
/// ```
|
||||||
impl<T, C> OutboundUpgrade<T> for NoiseConfig<IX, C>
|
impl<T, C> OutboundUpgrade<T> for NoiseConfig<IX, C>
|
||||||
where
|
where
|
||||||
NoiseConfig<IX, C>: UpgradeInfo,
|
NoiseConfig<IX, C>: UpgradeInfo,
|
||||||
@ -249,24 +286,33 @@ where
|
|||||||
{
|
{
|
||||||
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
||||||
type Error = NoiseError;
|
type Error = NoiseError;
|
||||||
type Future = Handshake<T, C>;
|
type Future = BoxFuture<'static, Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>>;
|
||||||
|
|
||||||
fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
|
fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
|
||||||
let legacy = self.legacy;
|
async move {
|
||||||
let identity = self.dh_keys.clone().into_identity();
|
let mut state = self.into_initiator(socket)?;
|
||||||
|
|
||||||
handshake::rt1_initiator(
|
handshake::send_identity(&mut state).await?;
|
||||||
socket,
|
handshake::recv_identity(&mut state).await?;
|
||||||
self.into_initiator(),
|
|
||||||
identity,
|
state.finish()
|
||||||
IdentityExchange::Mutual,
|
}
|
||||||
legacy,
|
.boxed()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handshake pattern XX /////////////////////////////////////////////////////
|
/// Implements the responder part of the `XX` noise handshake pattern.
|
||||||
|
///
|
||||||
|
/// `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 any information. The identities are then exchanged in the second
|
||||||
|
/// and third message.
|
||||||
|
///
|
||||||
|
/// ```raw
|
||||||
|
/// initiator --{}--> responder
|
||||||
|
/// initiator <-{id}- responder
|
||||||
|
/// initiator -{id}-> responder
|
||||||
|
/// ```
|
||||||
impl<T, C> InboundUpgrade<T> for NoiseConfig<XX, C>
|
impl<T, C> InboundUpgrade<T> for NoiseConfig<XX, C>
|
||||||
where
|
where
|
||||||
NoiseConfig<XX, C>: UpgradeInfo,
|
NoiseConfig<XX, C>: UpgradeInfo,
|
||||||
@ -275,22 +321,34 @@ where
|
|||||||
{
|
{
|
||||||
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
||||||
type Error = NoiseError;
|
type Error = NoiseError;
|
||||||
type Future = Handshake<T, C>;
|
type Future = BoxFuture<'static, Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>>;
|
||||||
|
|
||||||
fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
|
fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
|
||||||
let legacy = self.legacy;
|
async move {
|
||||||
let identity = self.dh_keys.clone().into_identity();
|
let mut state = self.into_responder(socket)?;
|
||||||
|
|
||||||
handshake::rt15_responder(
|
handshake::recv_empty(&mut state).await?;
|
||||||
socket,
|
handshake::send_identity(&mut state).await?;
|
||||||
self.into_responder(),
|
handshake::recv_identity(&mut state).await?;
|
||||||
identity,
|
|
||||||
IdentityExchange::Mutual,
|
state.finish()
|
||||||
legacy,
|
}
|
||||||
)
|
.boxed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implements the initiator part of the `XX` noise handshake pattern.
|
||||||
|
///
|
||||||
|
/// `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 any information. The identities are then exchanged in the second
|
||||||
|
/// and third message.
|
||||||
|
///
|
||||||
|
/// ```raw
|
||||||
|
/// initiator --{}--> responder
|
||||||
|
/// initiator <-{id}- responder
|
||||||
|
/// initiator -{id}-> responder
|
||||||
|
/// ```
|
||||||
impl<T, C> OutboundUpgrade<T> for NoiseConfig<XX, C>
|
impl<T, C> OutboundUpgrade<T> for NoiseConfig<XX, C>
|
||||||
where
|
where
|
||||||
NoiseConfig<XX, C>: UpgradeInfo,
|
NoiseConfig<XX, C>: UpgradeInfo,
|
||||||
@ -299,48 +357,67 @@ where
|
|||||||
{
|
{
|
||||||
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
||||||
type Error = NoiseError;
|
type Error = NoiseError;
|
||||||
type Future = Handshake<T, C>;
|
type Future = BoxFuture<'static, Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>>;
|
||||||
|
|
||||||
fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
|
fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
|
||||||
let legacy = self.legacy;
|
async move {
|
||||||
let identity = self.dh_keys.clone().into_identity();
|
let mut state = self.into_initiator(socket)?;
|
||||||
|
|
||||||
handshake::rt15_initiator(
|
handshake::send_empty(&mut state).await?;
|
||||||
socket,
|
handshake::recv_identity(&mut state).await?;
|
||||||
self.into_initiator(),
|
handshake::send_identity(&mut state).await?;
|
||||||
identity,
|
|
||||||
IdentityExchange::Mutual,
|
state.finish()
|
||||||
legacy,
|
}
|
||||||
)
|
.boxed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handshake pattern IK /////////////////////////////////////////////////////
|
/// Implements the responder part of the `IK` handshake pattern.
|
||||||
|
///
|
||||||
impl<T, C, R> InboundUpgrade<T> for NoiseConfig<IK, C, R>
|
/// `IK` is a single round-trip (2 messages) handshake.
|
||||||
|
///
|
||||||
|
/// 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
|
||||||
|
/// initiator <-{id}- responder
|
||||||
|
/// ```
|
||||||
|
impl<T, C> InboundUpgrade<T> for NoiseConfig<IK, C>
|
||||||
where
|
where
|
||||||
NoiseConfig<IK, C, R>: UpgradeInfo,
|
NoiseConfig<IK, C>: UpgradeInfo,
|
||||||
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
|
||||||
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
|
C: Protocol<C> + AsRef<[u8]> + Zeroize + Clone + Send + 'static,
|
||||||
{
|
{
|
||||||
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
||||||
type Error = NoiseError;
|
type Error = NoiseError;
|
||||||
type Future = Handshake<T, C>;
|
type Future = BoxFuture<'static, Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>>;
|
||||||
|
|
||||||
fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
|
fn upgrade_inbound(self, socket: T, _: Self::Info) -> Self::Future {
|
||||||
let legacy = self.legacy;
|
async move {
|
||||||
let identity = self.dh_keys.clone().into_identity();
|
let mut state = self.into_responder(socket)?;
|
||||||
|
|
||||||
handshake::rt1_responder(
|
handshake::recv_identity(&mut state).await?;
|
||||||
socket,
|
handshake::send_signature_only(&mut state).await?;
|
||||||
self.into_responder(),
|
|
||||||
identity,
|
state.finish()
|
||||||
IdentityExchange::Receive,
|
}
|
||||||
legacy,
|
.boxed()
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implements the initiator part of the `IK` handshake pattern.
|
||||||
|
///
|
||||||
|
/// `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`](snow::HandshakeState).
|
||||||
|
///
|
||||||
|
/// ```raw
|
||||||
|
/// initiator -{id}-> responder
|
||||||
|
/// initiator <-{id}- responder
|
||||||
|
/// ```
|
||||||
impl<T, C> OutboundUpgrade<T> for NoiseConfig<IK, C, (PublicKey<C>, identity::PublicKey)>
|
impl<T, C> OutboundUpgrade<T> for NoiseConfig<IK, C, (PublicKey<C>, identity::PublicKey)>
|
||||||
where
|
where
|
||||||
NoiseConfig<IK, C, (PublicKey<C>, identity::PublicKey)>: UpgradeInfo,
|
NoiseConfig<IK, C, (PublicKey<C>, identity::PublicKey)>: UpgradeInfo,
|
||||||
@ -349,27 +426,18 @@ where
|
|||||||
{
|
{
|
||||||
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
type Output = (RemoteIdentity<C>, NoiseOutput<T>);
|
||||||
type Error = NoiseError;
|
type Error = NoiseError;
|
||||||
type Future = Handshake<T, C>;
|
type Future = BoxFuture<'static, Result<(RemoteIdentity<C>, NoiseOutput<T>), NoiseError>>;
|
||||||
|
|
||||||
fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
|
fn upgrade_outbound(self, socket: T, _: Self::Info) -> Self::Future {
|
||||||
let session = self
|
async move {
|
||||||
.params
|
let mut state = self.into_initiator(socket)?;
|
||||||
.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(
|
handshake::send_identity(&mut state).await?;
|
||||||
socket,
|
handshake::recv_identity(&mut state).await?;
|
||||||
session,
|
|
||||||
self.dh_keys.into_identity(),
|
state.finish()
|
||||||
IdentityExchange::Send {
|
}
|
||||||
remote: self.remote.1,
|
.boxed()
|
||||||
},
|
|
||||||
self.legacy,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -479,51 +547,3 @@ pub struct LegacyConfig {
|
|||||||
/// libp2p implementations.
|
/// libp2p implementations.
|
||||||
pub recv_legacy_handshake: bool,
|
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -34,9 +34,24 @@ use zeroize::Zeroize;
|
|||||||
pub struct ProtocolParams(snow::params::NoiseParams);
|
pub struct ProtocolParams(snow::params::NoiseParams);
|
||||||
|
|
||||||
impl ProtocolParams {
|
impl ProtocolParams {
|
||||||
/// Turn the protocol parameters into a session builder.
|
pub(crate) fn into_builder<'b, C>(
|
||||||
pub(crate) fn into_builder(self) -> snow::Builder<'static> {
|
self,
|
||||||
snow::Builder::with_resolver(self.0, Box::new(Resolver))
|
prologue: &'b [u8],
|
||||||
|
private_key: &'b SecretKey<C>,
|
||||||
|
remote_public_key: Option<&'b PublicKey<C>>,
|
||||||
|
) -> snow::Builder<'b>
|
||||||
|
where
|
||||||
|
C: Zeroize + AsRef<[u8]> + Protocol<C>,
|
||||||
|
{
|
||||||
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,26 +133,27 @@ pub struct Keypair<T: Zeroize> {
|
|||||||
/// A DH keypair that is authentic w.r.t. a [`identity::PublicKey`].
|
/// A DH keypair that is authentic w.r.t. a [`identity::PublicKey`].
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AuthenticKeypair<T: Zeroize> {
|
pub struct AuthenticKeypair<T: Zeroize> {
|
||||||
keypair: Keypair<T>,
|
pub(crate) keypair: Keypair<T>,
|
||||||
identity: KeypairIdentity,
|
pub(crate) identity: KeypairIdentity,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Zeroize> AuthenticKeypair<T> {
|
impl<T: Zeroize> AuthenticKeypair<T> {
|
||||||
|
/// Returns the public DH key of this keypair.
|
||||||
|
pub fn public_dh_key(&self) -> &PublicKey<T> {
|
||||||
|
&self.keypair.public
|
||||||
|
}
|
||||||
|
|
||||||
/// Extract the public [`KeypairIdentity`] from this `AuthenticKeypair`,
|
/// Extract the public [`KeypairIdentity`] from this `AuthenticKeypair`,
|
||||||
/// dropping the DH `Keypair`.
|
/// 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 {
|
pub fn into_identity(self) -> KeypairIdentity {
|
||||||
self.identity
|
self.identity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Zeroize> std::ops::Deref for AuthenticKeypair<T> {
|
|
||||||
type Target = Keypair<T>;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.keypair
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The associated public identity of a DH keypair.
|
/// The associated public identity of a DH keypair.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct KeypairIdentity {
|
pub struct KeypairIdentity {
|
||||||
@ -288,3 +304,40 @@ impl rand::RngCore for Rng {
|
|||||||
impl rand::CryptoRng for Rng {}
|
impl rand::CryptoRng for Rng {}
|
||||||
|
|
||||||
impl snow::types::Random 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<X25519> = Keypair::<X25519>::new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -197,7 +197,7 @@ fn ik_xx() {
|
|||||||
let client_id_public = client_id.public();
|
let client_id_public = client_id.public();
|
||||||
|
|
||||||
let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap();
|
let server_dh = Keypair::<X25519>::new().into_authentic(&server_id).unwrap();
|
||||||
let server_dh_public = server_dh.public().clone();
|
let server_dh_public = server_dh.public_dh_key().clone();
|
||||||
let server_transport = TcpTransport::default()
|
let server_transport = TcpTransport::default()
|
||||||
.and_then(move |output, endpoint| {
|
.and_then(move |output, endpoint| {
|
||||||
if endpoint.is_listener() {
|
if endpoint.is_listener() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user