bugfix: setting correct LpPeerConfig during handshake

This commit is contained in:
Jędrzej Stuczyński
2026-03-06 10:18:45 +00:00
parent 93ac638765
commit 48dad0f16b
7 changed files with 116 additions and 36 deletions
+5
View File
@@ -65,6 +65,7 @@ impl LpPeerConfig {
rng.random(),
)
}
/// Creates a new client to exit config.
/// Inputs:
/// hop_id: this value must be in the range (1..=15). This function returns an error if this is not the case.
@@ -79,6 +80,7 @@ impl LpPeerConfig {
{
Self::new(rng, hop_id, true, false, censorship_resistance)
}
/// Creates a new client to an intermediate node config.
/// Inputs:
/// hop_id: this value must be in the range (1..=14). This function returns an error if this is not the case.
@@ -130,6 +132,7 @@ impl LpPeerConfig {
rng.random(),
)
}
fn build(
hop_id: u8,
is_exit: bool,
@@ -147,6 +150,7 @@ impl LpPeerConfig {
seed,
}
}
fn build_checked(
hop_id: u8,
is_exit: bool,
@@ -203,6 +207,7 @@ impl LpPeerConfig {
output_bytes[4..].copy_from_slice(&self.seed);
output_bytes
}
pub fn deserialize(bytes: &[u8]) -> Result<Self, LpError> {
if bytes.len() != LP_PEER_CONFIG_SIZE {
return Err(LpError::DeserializationError(format!(
+43 -13
View File
@@ -24,10 +24,31 @@ use nym_kkt::message::{KKTRequest, KKTResponse};
use rand09::SeedableRng;
use tracing::debug;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HandshakeMode {
// Client <> Entry
OneWayEntry,
// Client <> Exit
OneWayExit,
// Entry <> Exit
MutualInternode,
// in the future more variants will be supported (such as individual mix hops)
}
impl HandshakeMode {
pub fn is_mutual(&self) -> bool {
matches!(self, HandshakeMode::MutualInternode)
}
}
pub struct PSQHandshakeStateInitiator<'a, S> {
pub(super) inner_state: PSQHandshakeState<'a, S>,
pub(super) initiator_data: InitiatorData,
pub(super) mutual: bool,
/// The mode of the handshake (mutual node-node, client-entry, entry-exit)
pub(super) mode: HandshakeMode,
}
pub(crate) fn build_psq_principal<R>(
@@ -78,13 +99,23 @@ impl<'a, S> PSQHandshakeStateInitiator<'a, S>
where
S: LpHandshakeChannel + Unpin,
{
pub fn set_mutual_kkt(mut self) -> Result<Self, LpError> {
if self.inner_state.local_peer.kem_keypairs.is_none() {
return Err(LpError::PSQMutualInitiatorMissingKemKey);
}
fn lp_peer_config<R>(&self, rng: &mut R) -> Result<LpPeerConfig, LpError>
where
R: rand09::CryptoRng,
{
// for now we don't support censorship resistance flag
let censorship_resistance = false;
self.mutual = true;
Ok(self)
match self.mode {
HandshakeMode::OneWayEntry => Ok(LpPeerConfig::new_client_to_entry(
rng,
censorship_resistance,
)),
HandshakeMode::OneWayExit => {
LpPeerConfig::new_client_to_exit(rng, 1, censorship_resistance)
}
HandshakeMode::MutualInternode => LpPeerConfig::new_node_to_node(rng),
}
}
/// Attempt to send KKT request to begin the handshake
@@ -132,7 +163,7 @@ where
let ciphersuite = self.inner_state.local_peer.ciphersuite();
let kem = ciphersuite.kem();
let lp_peer_config = LpPeerConfig::new_client_to_entry(rng, false);
let lp_peer_config = self.lp_peer_config(rng)?;
// 1. retrieve the expected kem key hash. if we don't know it,
let dir_hash = self
@@ -141,7 +172,7 @@ where
.expected_kem_key_hash(ciphersuite)?;
// 2. prepare and send KKT request
let (mut initiator, kkt_request) = if self.mutual {
let (mut initiator, kkt_request) = if self.mode.is_mutual() {
// this has been verified when setting the mutual flag
let Some(local_encapsulation_key) = self.inner_state.local_peer.encoded_kem_key(kem)
else {
@@ -273,8 +304,8 @@ mod tests {
resp.ciphersuite = ciphersuite;
let initiator_data = InitiatorData::new(1, resp_remote);
let handshake_init =
PSQHandshakeState::new(conn_init, init).as_initiator(initiator_data);
let handshake_init = PSQHandshakeState::new(conn_init, init)
.as_initiator(initiator_data, HandshakeMode::OneWayEntry)?;
let mut init_rng = DeterministicRng09Send::new(u64_seeded_rng_09(1));
@@ -396,8 +427,7 @@ mod tests {
let initiator_data = InitiatorData::new(1, resp_remote);
let handshake_init = PSQHandshakeState::new(conn_init, init)
.as_initiator(initiator_data)
.set_mutual_kkt()?;
.as_initiator(initiator_data, HandshakeMode::MutualInternode)?;
let mut init_rng = DeterministicRng09Send::new(u64_seeded_rng_09(1));
+22 -9
View File
@@ -12,6 +12,8 @@ mod helpers;
pub mod initiator;
pub mod responder;
use crate::LpError;
use crate::psq::initiator::HandshakeMode;
pub use initiator::PSQHandshakeStateInitiator;
pub use responder::PSQHandshakeStateResponder;
@@ -107,12 +109,20 @@ where
}
}
pub fn as_initiator(self, initiator_data: InitiatorData) -> PSQHandshakeStateInitiator<'a, S> {
PSQHandshakeStateInitiator {
pub fn as_initiator(
self,
initiator_data: InitiatorData,
mode: HandshakeMode,
) -> Result<PSQHandshakeStateInitiator<'a, S>, LpError> {
if mode.is_mutual() && self.local_peer.kem_keypairs.is_none() {
return Err(LpError::PSQMutualInitiatorMissingKemKey);
}
Ok(PSQHandshakeStateInitiator {
initiator_data,
inner_state: self,
mutual: false,
}
mode,
})
}
pub fn as_responder(self, responder_data: ResponderData) -> PSQHandshakeStateResponder<'a, S> {
@@ -160,8 +170,10 @@ mod tests {
resp.ciphersuite = ciphersuite;
let resp_remote = resp.as_remote();
let handshake_init = PSQHandshakeState::new(conn_init, init)
.as_initiator(InitiatorData::new(1, resp_remote));
let handshake_init = PSQHandshakeState::new(conn_init, init).as_initiator(
InitiatorData::new(1, resp_remote),
HandshakeMode::OneWayEntry,
)?;
let handshake_resp =
PSQHandshakeState::new(conn_resp, resp).as_responder(ResponderData::default());
@@ -232,9 +244,10 @@ mod tests {
let resp_remote = resp.as_remote();
let init_remote = init.as_remote();
let handshake_init = PSQHandshakeState::new(conn_init, init)
.as_initiator(InitiatorData::new(1, resp_remote))
.set_mutual_kkt()?;
let handshake_init = PSQHandshakeState::new(conn_init, init).as_initiator(
InitiatorData::new(1, resp_remote),
HandshakeMode::MutualInternode,
)?;
let handshake_resp = PSQHandshakeState::new(conn_resp, resp).as_responder(
ResponderData::default()
.with_initiator_kem_hashes(init_remote.expected_kem_key_digests),
+26 -3
View File
@@ -9,6 +9,7 @@ use crate::codec::{decrypt_lp_packet, encrypt_lp_packet};
use crate::packet::{EncryptedLpPacket, LpHeader, LpMessage, LpPacket};
use crate::peer::{LpLocalPeer, LpRemotePeer};
use crate::peer_config::LpReceiverIndex;
use crate::psq::initiator::HandshakeMode;
use crate::psq::{
InitiatorData, PSQHandshakeState, PSQHandshakeStateInitiator, PSQHandshakeStateResponder,
ResponderData,
@@ -154,12 +155,34 @@ impl LpTransportSession {
local_peer: LpLocalPeer,
remote_peer: LpRemotePeer,
remote_protocol_version: u8,
) -> PSQHandshakeStateInitiator<'_, S>
mode: HandshakeMode,
) -> Result<PSQHandshakeStateInitiator<'_, S>, LpError>
where
S: LpHandshakeChannel + Unpin,
{
PSQHandshakeState::new(connection, local_peer)
.as_initiator(InitiatorData::new(remote_protocol_version, remote_peer))
PSQHandshakeState::new(connection, local_peer).as_initiator(
InitiatorData::new(remote_protocol_version, remote_peer),
mode,
)
}
/// Helper function to create `PSQHandshakeState` for the handshake initiator for mutual KKT
pub fn psq_handshake_initiator_mutual_internode<S>(
connection: &'_ mut S,
local_peer: LpLocalPeer,
remote_peer: LpRemotePeer,
remote_protocol_version: u8,
) -> Result<PSQHandshakeStateInitiator<'_, S>, LpError>
where
S: LpHandshakeChannel + Unpin,
{
Self::psq_handshake_initiator(
connection,
local_peer,
remote_peer,
remote_protocol_version,
HandshakeMode::MutualInternode,
)
}
/// Helper function to create `PSQHandshakeState` for the handshake responder
+14 -9
View File
@@ -17,9 +17,10 @@ mod tests {
use nym_lp::peer::LpLocalPeer;
use nym_node::config::{LpConfig, LpDebug};
use nym_node::node::GatewayStorage;
use nym_node::node::lp::control::ingress::client_handler::LpConnectionHandler;
use nym_node::node::lp::control::ingress::client_handler::LpClientConnectionHandler;
use nym_node::node::lp::error::LpHandlerError;
use nym_node::node::lp::{SharedLpControlState, SharedLpState};
use nym_node::node::lp::state::{ActiveLpSessions, NestedConnectionsManager};
use nym_node::node::lp::{SharedLpClientControlState, SharedLpState};
use nym_node::wireguard::{PeerManager, PeerRegistrator};
use nym_registration_client::{LpClientError, LpRegistrationClient};
use nym_test_utils::helpers::{CryptoRng09, seeded_rng};
@@ -35,7 +36,7 @@ mod tests {
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::sync::Arc;
use tokio::sync::Semaphore;
use tokio::sync::mpsc::Receiver;
use tokio::sync::mpsc::{Receiver, channel};
use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
use tracing::error;
@@ -120,7 +121,7 @@ mod tests {
enum SpawnedLpConnectionHandlerState {
NotCreated,
Ready {
handler: LpConnectionHandler<MockIOStream>,
handler: LpClientConnectionHandler<MockIOStream>,
},
Running {
handle: JoinHandle<Option<Result<(), LpHandlerError>>>,
@@ -130,7 +131,7 @@ mod tests {
struct Gateway {
base: Party,
lp_state: SharedLpControlState,
lp_state: SharedLpClientControlState,
ip_pool: IpPool,
mock_peer_controller: SpawnedPeerController,
@@ -216,6 +217,9 @@ mod tests {
let (mock_peer_controller, peer_controller_state) =
mock_peer_controller(peer_request_rx);
let (connection_ctrl_sender, _connection_manager_receiver) = channel(42);
let nested_connections_manager = NestedConnectionsManager::new(connection_ctrl_sender);
// registering particular responses for peer controller is up to given test
let ecash_verifier = Arc::new(ecash_verifier);
@@ -225,7 +229,7 @@ mod tests {
upgrade_mode_details,
);
let lp_state = SharedLpControlState {
let lp_state = SharedLpClientControlState {
local_lp_peer: base.peer.clone(),
forward_semaphore,
@@ -235,8 +239,9 @@ mod tests {
shared: SharedLpState {
metrics: Default::default(),
lp_config,
session_states: Arc::new(Default::default()),
session_states: ActiveLpSessions::new(),
},
nested_connections_manager,
};
Ok(Gateway {
@@ -262,7 +267,7 @@ mod tests {
};
self.lp_connection_handler = SpawnedLpConnectionHandlerState::Ready {
handler: LpConnectionHandler::new(
handler: LpClientConnectionHandler::new(
client_connection,
client_address,
self.lp_state.clone(),
@@ -290,7 +295,7 @@ mod tests {
}
fn spawn_lp_handler(&mut self) {
let SpawnedLpConnectionHandlerState::Ready { handler } = mem::replace(
let SpawnedLpConnectionHandlerState::Ready { mut handler } = mem::replace(
&mut self.lp_connection_handler,
SpawnedLpConnectionHandlerState::NotCreated,
) else {
@@ -14,6 +14,7 @@ use nym_crypto::asymmetric::{ed25519, x25519};
use nym_lp::LpTransportSession;
use nym_lp::peer::{DHKeyPair, LpLocalPeer, LpRemotePeer};
use nym_lp::peer_config::LpReceiverIndex;
use nym_lp::psq::initiator::HandshakeMode;
use nym_lp::transport::traits::LpTransportChannel;
use nym_lp::transport::{LpHandshakeChannel, LpTransportError};
use nym_lp::{Ciphersuite, packet::EncryptedLpPacket, packet::version};
@@ -396,7 +397,8 @@ where
local_peer,
remote_peer,
protocol_version,
)
HandshakeMode::OneWayEntry,
)?
.complete_handshake()
.await?;
@@ -28,6 +28,7 @@ use nym_crypto::asymmetric::{ed25519, x25519};
use nym_lp::packet::version;
use nym_lp::packet::{EncryptedLpPacket, LpMessage};
use nym_lp::peer::{DHKeyPair, LpLocalPeer, LpRemotePeer};
use nym_lp::psq::initiator::HandshakeMode;
use nym_lp::transport::LpHandshakeChannel;
use nym_lp::transport::traits::LpTransportChannel;
use nym_lp::{Ciphersuite, KEM, LpTransportSession};
@@ -185,7 +186,8 @@ impl NestedLpSession {
local_peer,
remote_peer,
protocol_version,
)
HandshakeMode::OneWayExit,
)?
.complete_handshake()
.await?;