restoring nym-lp tests
This commit is contained in:
@@ -262,7 +262,7 @@ impl ForwardPacketData {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum LpMessage {
|
||||
/// The party is busy
|
||||
Busy,
|
||||
|
||||
@@ -53,7 +53,7 @@ impl EncryptedLpPacket {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct LpPacket {
|
||||
pub(crate) header: LpHeader,
|
||||
pub(crate) message: LpMessage,
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main};
|
||||
use nym_lp::replay::ReceivingKeyCounterValidator;
|
||||
use nym_test_utils::helpers::deterministic_rng_09;
|
||||
use parking_lot::Mutex;
|
||||
use rand09::Rng;
|
||||
use std::sync::Arc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
fn bench_sequential_counters(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group("replay_sequential");
|
||||
@@ -75,19 +74,15 @@ fn bench_thread_safety(c: &mut Criterion) {
|
||||
BenchmarkId::new("thread_safe_validator", size),
|
||||
&size,
|
||||
|b, &size| {
|
||||
let validator = Arc::new(Mutex::new(ReceivingKeyCounterValidator::default()));
|
||||
let mut validator = ReceivingKeyCounterValidator::default();
|
||||
let counters: Vec<u64> = (0..size).collect();
|
||||
|
||||
b.iter(|| {
|
||||
for &counter in &counters {
|
||||
let result = {
|
||||
let guard = validator.lock();
|
||||
black_box(guard.will_accept_branchless(counter))
|
||||
};
|
||||
let result = { black_box(validator.will_accept_branchless(counter)) };
|
||||
|
||||
if result.is_ok() {
|
||||
let mut guard = validator.lock();
|
||||
let _ = black_box(guard.mark_did_receive_branchless(counter));
|
||||
let _ = black_box(validator.mark_did_receive_branchless(counter));
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -202,7 +197,7 @@ fn bench_concurrency_scaling(c: &mut Criterion) {
|
||||
let mut success_count = 0;
|
||||
for i in 0..100 {
|
||||
let counter = t * 1000 + i;
|
||||
let mut guard = validator_clone.lock();
|
||||
let mut guard = validator_clone.lock().unwrap();
|
||||
if guard.mark_did_receive_branchless(counter as u64).is_ok() {
|
||||
success_count += 1;
|
||||
}
|
||||
|
||||
+210
-900
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,9 @@ pub enum LpError {
|
||||
#[error("Attempted operation on closed session")]
|
||||
SessionClosed,
|
||||
|
||||
#[error("There already exists an LP session with id {0:?}")]
|
||||
DuplicateSessionId(SessionId),
|
||||
|
||||
#[error("Internal error: {0}")]
|
||||
Internal(String),
|
||||
|
||||
@@ -112,6 +115,9 @@ pub enum LpError {
|
||||
|
||||
#[error("transport failure: {0}")]
|
||||
TransportFailure(#[from] LpTransportError),
|
||||
|
||||
#[error("the current session is not in transport state")]
|
||||
NotInTransport,
|
||||
}
|
||||
|
||||
impl LpError {
|
||||
|
||||
@@ -135,240 +135,3 @@ pub fn sessions_for_tests() -> (LpSession, LpSession) {
|
||||
pub fn mock_session_for_test() -> LpSession {
|
||||
SessionsMock::mock_initiator()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::session_manager::SessionManager;
|
||||
use crate::{LpError, SessionsMock, mock_session_for_test};
|
||||
use bytes::BytesMut;
|
||||
use nym_kkt_ciphersuite::{Ciphersuite, HashFunction, IntoEnumIterator, KEM, SignatureScheme};
|
||||
|
||||
// Import the new standalone functions
|
||||
use crate::codec::serialize_lp_packet;
|
||||
|
||||
#[test]
|
||||
fn test_replay_protection_integration() {
|
||||
todo!()
|
||||
// for kem in kem_list() {
|
||||
// // Create session
|
||||
// let mut session = mock_session_for_test();
|
||||
//
|
||||
// // === Packet 1 (Counter 0 - Should succeed) ===
|
||||
// let packet1 = LpPacket {
|
||||
// header: LpHeader {
|
||||
// protocol_version: 1,
|
||||
// reserved: [0u8; 3],
|
||||
// receiver_idx: 42, // Matches session's sending_index assumption for this test
|
||||
// counter: 0,
|
||||
// },
|
||||
// message: LpMessage::Busy,
|
||||
// trailer: [0u8; TRAILER_LEN],
|
||||
// };
|
||||
//
|
||||
// // Serialize packet
|
||||
// let mut buf1 = BytesMut::new();
|
||||
// serialize_lp_packet(&packet1, &mut buf1, None).unwrap();
|
||||
//
|
||||
// // Parse packet
|
||||
// let parsed_packet1 = parse_lp_packet(&buf1, None).unwrap();
|
||||
//
|
||||
// // Perform replay check (should pass)
|
||||
// session
|
||||
// .receiving_counter_quick_check(parsed_packet1.header.counter)
|
||||
// .expect("Initial packet failed replay check");
|
||||
//
|
||||
// // Mark received (simulating successful processing)
|
||||
// session
|
||||
// .receiving_counter_mark(parsed_packet1.header.counter)
|
||||
// .expect("Failed to mark initial packet received");
|
||||
//
|
||||
// // === Packet 2 (Counter 0 - Replay, should fail check) ===
|
||||
// let packet2 = LpPacket {
|
||||
// header: LpHeader {
|
||||
// protocol_version: 1,
|
||||
// reserved: [0u8; 3],
|
||||
// receiver_idx: 42,
|
||||
// counter: 0, // Same counter as before (replay)
|
||||
// },
|
||||
// message: LpMessage::Busy,
|
||||
// trailer: [0u8; TRAILER_LEN],
|
||||
// };
|
||||
//
|
||||
// // Serialize packet
|
||||
// let mut buf2 = BytesMut::new();
|
||||
// serialize_lp_packet(&packet2, &mut buf2, None).unwrap();
|
||||
//
|
||||
// // Parse packet
|
||||
// let parsed_packet2 = parse_lp_packet(&buf2, None).unwrap();
|
||||
//
|
||||
// // Perform replay check (should fail)
|
||||
// let replay_result =
|
||||
// session.receiving_counter_quick_check(parsed_packet2.header.counter);
|
||||
// assert!(replay_result.is_err());
|
||||
// match replay_result.unwrap_err() {
|
||||
// LpError::Replay(e) => {
|
||||
// assert!(matches!(e, crate::replay::ReplayError::DuplicateCounter));
|
||||
// }
|
||||
// e => panic!("Expected replay error, got {:?}", e),
|
||||
// }
|
||||
// // Do not mark received as it failed validation
|
||||
//
|
||||
// // === Packet 3 (Counter 1 - Should succeed) ===
|
||||
// let packet3 = LpPacket {
|
||||
// header: LpHeader {
|
||||
// protocol_version: 1,
|
||||
// reserved: [0u8; 3],
|
||||
// receiver_idx: 42,
|
||||
// counter: 1, // Incremented counter
|
||||
// },
|
||||
// message: LpMessage::Busy,
|
||||
// trailer: [0u8; TRAILER_LEN],
|
||||
// };
|
||||
//
|
||||
// // Serialize packet
|
||||
// let mut buf3 = BytesMut::new();
|
||||
// serialize_lp_packet(&packet3, &mut buf3, None).unwrap();
|
||||
//
|
||||
// // Parse packet
|
||||
// let parsed_packet3 = parse_lp_packet(&buf3, None).unwrap();
|
||||
//
|
||||
// // Perform replay check (should pass)
|
||||
// session
|
||||
// .receiving_counter_quick_check(parsed_packet3.header.counter)
|
||||
// .expect("Packet 3 failed replay check");
|
||||
//
|
||||
// // Mark received
|
||||
// session
|
||||
// .receiving_counter_mark(parsed_packet3.header.counter)
|
||||
// .expect("Failed to mark packet 3 received");
|
||||
//
|
||||
// // Verify validator state directly on the session
|
||||
// let state = session.current_packet_cnt();
|
||||
// assert_eq!(state.0, 2); // Next expected counter (correct - was 1, now expects 2)
|
||||
// assert_eq!(state.1, 2); // Total marked received (correct - packets 1 and 3)
|
||||
// }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_session_manager_integration() {
|
||||
// Create session manager
|
||||
let mut local_manager = SessionManager::new();
|
||||
let mut remote_manager = SessionManager::new();
|
||||
|
||||
for kem in KEM::iter() {
|
||||
todo!()
|
||||
// // Generate Ed25519 keypairs for PSQ authentication
|
||||
// let (init, resp) = mock_peers(kem);
|
||||
//
|
||||
// let mut ciphersuite = Ciphersuite::resolve_ciphersuite(
|
||||
// kem,
|
||||
// HashFunction::Blake3,
|
||||
// SignatureScheme::Ed25519,
|
||||
// None,
|
||||
// );
|
||||
//
|
||||
// // Use fixed receiver_index for deterministic test
|
||||
// let receiver_index: u32 = 54321;
|
||||
//
|
||||
// let sessions = SessionsMock::mock_post_handshake(receiver_index);
|
||||
// let local_session = sessions.initiator;
|
||||
// let remote_session = sessions.responder;
|
||||
//
|
||||
// // Create a session via manager
|
||||
// let _ = local_manager.create_session_state_machine(local_session);
|
||||
// let _ = remote_manager.create_session_state_machine(remote_session);
|
||||
//
|
||||
// // === Packet 1 (Counter 0 - Should succeed) ===
|
||||
// let packet1 = LpPacket {
|
||||
// header: LpHeader {
|
||||
// protocol_version: 1,
|
||||
// reserved: [0u8; 3],
|
||||
// receiver_idx: receiver_index,
|
||||
// counter: 0,
|
||||
// },
|
||||
// message: LpMessage::Busy,
|
||||
// trailer: [0u8; TRAILER_LEN],
|
||||
// };
|
||||
//
|
||||
// // Serialize
|
||||
// let mut buf1 = BytesMut::new();
|
||||
// serialize_lp_packet(&packet1, &mut buf1, None).unwrap();
|
||||
//
|
||||
// // Parse
|
||||
// let parsed_packet1 = parse_lp_packet(&buf1, None).unwrap();
|
||||
//
|
||||
// // Process via SessionManager method (which should handle checks + marking)
|
||||
// // NOTE: We might need a method on SessionManager/LpSession like `process_incoming_packet`
|
||||
// // that encapsulates parse -> check -> process_noise -> mark.
|
||||
// // For now, we simulate the steps using the retrieved session.
|
||||
//
|
||||
// // Perform replay check
|
||||
// local_manager
|
||||
// .receiving_counter_quick_check(receiver_index, parsed_packet1.header.counter)
|
||||
// .expect("Packet 1 check failed");
|
||||
// // Mark received
|
||||
// local_manager
|
||||
// .receiving_counter_mark(receiver_index, parsed_packet1.header.counter)
|
||||
// .expect("Packet 1 mark failed");
|
||||
//
|
||||
// // === Packet 2 (Counter 1 - Should succeed on same session) ===
|
||||
// let packet2 = LpPacket {
|
||||
// header: LpHeader {
|
||||
// protocol_version: 1,
|
||||
// reserved: [0u8; 3],
|
||||
// receiver_idx: receiver_index,
|
||||
// counter: 1,
|
||||
// },
|
||||
// message: LpMessage::Busy,
|
||||
// trailer: [0u8; TRAILER_LEN],
|
||||
// };
|
||||
//
|
||||
// // Serialize
|
||||
// let mut buf2 = BytesMut::new();
|
||||
// serialize_lp_packet(&packet2, &mut buf2, None).unwrap();
|
||||
//
|
||||
// // Parse
|
||||
// let parsed_packet2 = parse_lp_packet(&buf2, None).unwrap();
|
||||
//
|
||||
// // Perform replay check
|
||||
// local_manager
|
||||
// .receiving_counter_quick_check(receiver_index, parsed_packet2.header.counter)
|
||||
// .expect("Packet 2 check failed");
|
||||
// // Mark received
|
||||
// local_manager
|
||||
// .receiving_counter_mark(receiver_index, parsed_packet2.header.counter)
|
||||
// .expect("Packet 2 mark failed");
|
||||
//
|
||||
// // === Packet 3 (Counter 0 - Replay, should fail check) ===
|
||||
// let packet3 = LpPacket {
|
||||
// header: LpHeader {
|
||||
// protocol_version: 1,
|
||||
// reserved: [0u8; 3],
|
||||
// receiver_idx: receiver_index,
|
||||
// counter: 0, // Replay of first packet
|
||||
// },
|
||||
// message: LpMessage::Busy,
|
||||
// trailer: [0u8; TRAILER_LEN],
|
||||
// };
|
||||
//
|
||||
// // Serialize
|
||||
// let mut buf3 = BytesMut::new();
|
||||
// serialize_lp_packet(&packet3, &mut buf3, None).unwrap();
|
||||
//
|
||||
// // Parse
|
||||
// let parsed_packet3 = parse_lp_packet(&buf3, None).unwrap();
|
||||
//
|
||||
// // Perform replay check (should fail)
|
||||
// let replay_result = local_manager
|
||||
// .receiving_counter_quick_check(receiver_index, parsed_packet3.header.counter);
|
||||
// assert!(replay_result.is_err());
|
||||
// match replay_result.unwrap_err() {
|
||||
// LpError::Replay(e) => {
|
||||
// assert!(matches!(e, crate::replay::ReplayError::DuplicateCounter));
|
||||
// }
|
||||
// e => panic!("Expected replay error for packet 3, got {:?}", e),
|
||||
// }
|
||||
// // Do not mark received
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ pub(crate) const UDP_PAYLOAD_SIZE: usize = MTU - UDP_OVERHEAD;
|
||||
|
||||
pub use nym_lp_packet::version;
|
||||
|
||||
pub(crate) trait LpPacketReplayExt {
|
||||
pub trait LpPacketReplayExt {
|
||||
/// Validate packet counter against a replay protection validator
|
||||
///
|
||||
/// This performs a quick check to see if the packet counter is valid before
|
||||
|
||||
@@ -152,7 +152,7 @@ pub fn mock_peer() -> LpLocalPeer {
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "mock", test))]
|
||||
pub fn random_peer<'a, R: rand09::CryptoRng + rand09::RngCore>(rng: &mut R) -> LpLocalPeer {
|
||||
pub fn random_peer<R: rand09::CryptoRng + rand09::RngCore>(rng: &mut R) -> LpLocalPeer {
|
||||
let x25519 = Arc::new(nym_kkt::key_utils::generate_keypair_x25519(rng));
|
||||
|
||||
LpLocalPeer {
|
||||
|
||||
@@ -214,7 +214,6 @@ mod tests {
|
||||
let conn_resp = conn_resp.leak();
|
||||
|
||||
let (mut init, mut resp) = mock_peers();
|
||||
let init_remote = init.as_remote();
|
||||
let resp_remote = resp.as_remote();
|
||||
|
||||
let ciphersuite = Ciphersuite::default().with_kem(kem);
|
||||
@@ -246,8 +245,8 @@ mod tests {
|
||||
let responder_x25519_keypair = resp.x25519();
|
||||
|
||||
let kkt_responder = KKTResponder::new(
|
||||
&responder_x25519_keypair,
|
||||
&resp_keys,
|
||||
responder_x25519_keypair,
|
||||
resp_keys,
|
||||
&supported_hash,
|
||||
&supported_sigs,
|
||||
&[1],
|
||||
@@ -282,11 +281,6 @@ mod tests {
|
||||
.await??;
|
||||
responder.read_message(&msg, &mut []).unwrap();
|
||||
|
||||
// Get the authenticator out here, so we can deserialize the session later.
|
||||
let Some(initiator_authenticator) = responder.initiator_authenticator() else {
|
||||
panic!("No initiator authenticator found")
|
||||
};
|
||||
|
||||
// 4 send PSQ response
|
||||
let mut buf = vec![0u8; PSQ_MSG2_SIZE];
|
||||
let n = responder.write_message(&[], &mut buf).unwrap();
|
||||
@@ -304,7 +298,7 @@ mod tests {
|
||||
let mut r_transport = responder.into_session().unwrap();
|
||||
|
||||
// test serialization, deserialization
|
||||
let mut channel_i = session_init.active_transport();
|
||||
let channel_i = session_init.active_transport();
|
||||
let mut channel_r = r_transport.transport_channel().unwrap();
|
||||
|
||||
assert_eq!(channel_i.identifier(), channel_r.identifier());
|
||||
@@ -312,13 +306,13 @@ mod tests {
|
||||
let app_data_i = b"Derived session hey".as_slice();
|
||||
let app_data_r = b"Derived session ho".as_slice();
|
||||
|
||||
let ct_i = encrypt_data(app_data_i, &mut channel_i)?;
|
||||
let ct_i = encrypt_data(app_data_i, channel_i)?;
|
||||
let pt_r = decrypt_data(&ct_i, &mut channel_r)?;
|
||||
|
||||
assert_eq!(app_data_i, pt_r);
|
||||
|
||||
let ct_r = encrypt_data(app_data_r, &mut channel_r)?;
|
||||
let pt_i = decrypt_data(&ct_r, &mut channel_i)?;
|
||||
let pt_i = decrypt_data(&ct_r, channel_i)?;
|
||||
|
||||
assert_eq!(app_data_r, pt_i);
|
||||
}
|
||||
|
||||
@@ -172,21 +172,21 @@ mod tests {
|
||||
);
|
||||
|
||||
// test serialization, deserialization
|
||||
let mut channel_i = session_init.active_transport();
|
||||
let mut channel_r = session_resp.active_transport();
|
||||
let channel_i = session_init.active_transport();
|
||||
let channel_r = session_resp.active_transport();
|
||||
|
||||
assert_eq!(channel_i.identifier(), channel_r.identifier());
|
||||
|
||||
let app_data_i = b"Derived session hey".as_slice();
|
||||
let app_data_r = b"Derived session ho".as_slice();
|
||||
|
||||
let ct_i = encrypt_data(app_data_i, &mut channel_i)?;
|
||||
let pt_r = decrypt_data(&ct_i, &mut channel_r)?;
|
||||
let ct_i = encrypt_data(app_data_i, channel_i)?;
|
||||
let pt_r = decrypt_data(&ct_i, channel_r)?;
|
||||
|
||||
assert_eq!(app_data_i, pt_r);
|
||||
|
||||
let ct_r = encrypt_data(app_data_r, &mut channel_r)?;
|
||||
let pt_i = decrypt_data(&ct_r, &mut channel_i)?;
|
||||
let ct_r = encrypt_data(app_data_r, channel_r)?;
|
||||
let pt_i = decrypt_data(&ct_r, channel_i)?;
|
||||
|
||||
assert_eq!(app_data_r, pt_i);
|
||||
}
|
||||
@@ -218,8 +218,8 @@ mod tests {
|
||||
HashFunction::SHA256,
|
||||
];
|
||||
let kkt_responder = KKTResponder::new(
|
||||
&responder_x25519_keypair,
|
||||
&resp_keys,
|
||||
responder_x25519_keypair,
|
||||
resp_keys,
|
||||
&supported_hash,
|
||||
&supported_sigs,
|
||||
&[protocol_version],
|
||||
|
||||
@@ -233,7 +233,6 @@ mod tests {
|
||||
let conn_resp = conn_resp.leak();
|
||||
|
||||
let (mut init, mut resp) = mock_peers();
|
||||
let init_remote = init.as_remote();
|
||||
let resp_remote = resp.as_remote();
|
||||
|
||||
let ciphersuite = Ciphersuite::default().with_kem(kem);
|
||||
@@ -314,7 +313,7 @@ mod tests {
|
||||
|
||||
// test serialization, deserialization
|
||||
let mut channel_i = i_transport.transport_channel().unwrap();
|
||||
let mut channel_r = session_resp.active_transport();
|
||||
let channel_r = session_resp.active_transport();
|
||||
|
||||
assert_eq!(channel_i.identifier(), channel_r.identifier());
|
||||
|
||||
@@ -322,11 +321,11 @@ mod tests {
|
||||
let app_data_r = b"Derived session ho".as_slice();
|
||||
|
||||
let ct_i = encrypt_data(app_data_i, &mut channel_i)?;
|
||||
let pt_r = decrypt_data(&ct_i, &mut channel_r)?;
|
||||
let pt_r = decrypt_data(&ct_i, channel_r)?;
|
||||
|
||||
assert_eq!(app_data_i, pt_r);
|
||||
|
||||
let ct_r = encrypt_data(app_data_r, &mut channel_r)?;
|
||||
let ct_r = encrypt_data(app_data_r, channel_r)?;
|
||||
let pt_i = decrypt_data(&ct_r, &mut channel_i)?;
|
||||
|
||||
assert_eq!(app_data_r, pt_i);
|
||||
|
||||
@@ -38,6 +38,16 @@ const N_WORDS: usize = 16;
|
||||
/// Total number of bits in the bitmap
|
||||
const N_BITS: usize = WORD_SIZE * N_WORDS;
|
||||
|
||||
/// Current packet count statistics
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub struct PacketCount {
|
||||
/// the next expected counter value
|
||||
pub next: u64,
|
||||
|
||||
/// the total number of received packets
|
||||
pub received: u64,
|
||||
}
|
||||
|
||||
/// Validator for receiving key counters to prevent replay attacks.
|
||||
///
|
||||
/// This structure maintains a bitmap of received packets and validates
|
||||
@@ -205,11 +215,14 @@ impl ReceivingKeyCounterValidator {
|
||||
|
||||
/// Returns the current packet count statistics.
|
||||
///
|
||||
/// Returns a tuple of `(next, receive_cnt)` where:
|
||||
/// Returns a struct consisting of `(next, receive_cnt)` where:
|
||||
/// - `next` is the next expected counter value
|
||||
/// - `receive_cnt` is the total number of received packets
|
||||
pub fn current_packet_cnt(&self) -> (u64, u64) {
|
||||
(self.next, self.receive_cnt)
|
||||
pub fn current_packet_cnt(&self) -> PacketCount {
|
||||
PacketCount {
|
||||
next: self.next,
|
||||
received: self.receive_cnt,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
@@ -481,7 +494,10 @@ mod tests {
|
||||
let mut validator = ReceivingKeyCounterValidator::default();
|
||||
|
||||
// Initial state
|
||||
let (next, count) = validator.current_packet_cnt();
|
||||
let PacketCount {
|
||||
next,
|
||||
received: count,
|
||||
} = validator.current_packet_cnt();
|
||||
assert_eq!(next, 0);
|
||||
assert_eq!(count, 0);
|
||||
|
||||
@@ -490,21 +506,30 @@ mod tests {
|
||||
assert!(validator.mark_did_receive_branchless(1).is_ok());
|
||||
assert!(validator.mark_did_receive_branchless(2).is_ok());
|
||||
|
||||
let (next, count) = validator.current_packet_cnt();
|
||||
let PacketCount {
|
||||
next,
|
||||
received: count,
|
||||
} = validator.current_packet_cnt();
|
||||
assert_eq!(next, 3);
|
||||
assert_eq!(count, 3);
|
||||
|
||||
// After an out of order packet
|
||||
assert!(validator.mark_did_receive_branchless(10).is_ok());
|
||||
|
||||
let (next, count) = validator.current_packet_cnt();
|
||||
let PacketCount {
|
||||
next,
|
||||
received: count,
|
||||
} = validator.current_packet_cnt();
|
||||
assert_eq!(next, 11);
|
||||
assert_eq!(count, 4);
|
||||
|
||||
// After a packet from the past (within window)
|
||||
assert!(validator.mark_did_receive_branchless(5).is_ok());
|
||||
|
||||
let (next, count) = validator.current_packet_cnt();
|
||||
let PacketCount {
|
||||
next,
|
||||
received: count,
|
||||
} = validator.current_packet_cnt();
|
||||
assert_eq!(next, 11); // Next doesn't change
|
||||
assert_eq!(count, 5); // Count increases
|
||||
}
|
||||
@@ -553,7 +578,7 @@ mod tests {
|
||||
assert!(validator.mark_did_receive_branchless(first_jump).is_ok());
|
||||
|
||||
// Verify next counter is updated
|
||||
let (next, _) = validator.current_packet_cnt();
|
||||
let PacketCount { next, .. } = validator.current_packet_cnt();
|
||||
assert_eq!(next, first_jump + 1);
|
||||
|
||||
// Second large jump, even further ahead
|
||||
@@ -561,7 +586,7 @@ mod tests {
|
||||
assert!(validator.mark_did_receive_branchless(second_jump).is_ok());
|
||||
|
||||
// Verify next counter is updated again
|
||||
let (next, _) = validator.current_packet_cnt();
|
||||
let PacketCount { next, .. } = validator.current_packet_cnt();
|
||||
assert_eq!(next, second_jump + 1);
|
||||
|
||||
// Test packets within the new window
|
||||
@@ -726,10 +751,10 @@ mod tests {
|
||||
|
||||
// Check final state of the validator
|
||||
let final_state = validator.lock().unwrap();
|
||||
let (_next, receive_cnt) = final_state.current_packet_cnt();
|
||||
let count = final_state.current_packet_cnt();
|
||||
|
||||
// Verify that the received count matches our successful operations
|
||||
assert_eq!(receive_cnt, total_successes as u64);
|
||||
assert_eq!(count.received, total_successes as u64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -11,6 +11,7 @@ use crate::psq::{
|
||||
InitiatorData, PSQHandshakeState, PSQHandshakeStateInitiator, PSQHandshakeStateResponder,
|
||||
ResponderData,
|
||||
};
|
||||
use crate::replay::validator::PacketCount;
|
||||
use crate::{LpError, LpMessage, LpPacket, ReceivingKeyCounterValidator};
|
||||
use libcrux_psq::handshake::types::{Authenticator, DHPublicKey};
|
||||
use libcrux_psq::session::{Session, SessionBinding};
|
||||
@@ -162,7 +163,7 @@ impl LpSession {
|
||||
self.psq_session.identifier()
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u32 {
|
||||
pub fn receiver_index(&self) -> u32 {
|
||||
let TODO = "this is temporary...";
|
||||
let id = self.psq_session.identifier();
|
||||
u32::from_le_bytes([id[0], id[1], id[2], id[3]])
|
||||
@@ -177,7 +178,12 @@ impl LpSession {
|
||||
|
||||
pub fn next_packet(&mut self, message: LpMessage) -> Result<LpPacket, LpError> {
|
||||
let counter = self.next_counter();
|
||||
let header = LpHeader::new(self.id(), counter, self.protocol_version, message.typ());
|
||||
let header = LpHeader::new(
|
||||
self.receiver_index(),
|
||||
counter,
|
||||
self.protocol_version,
|
||||
message.typ(),
|
||||
);
|
||||
let packet = LpPacket::new(header, message);
|
||||
Ok(packet)
|
||||
}
|
||||
@@ -236,7 +242,7 @@ impl LpSession {
|
||||
/// A tuple containing:
|
||||
/// * The next expected counter value for incoming packets
|
||||
/// * The total number of received packets
|
||||
pub fn current_packet_cnt(&self) -> (u64, u64) {
|
||||
pub fn current_packet_cnt(&self) -> PacketCount {
|
||||
self.receiving_counter.current_packet_cnt()
|
||||
}
|
||||
|
||||
@@ -280,7 +286,7 @@ impl LpSession {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{ReplayError, SessionsMock, sessions_for_tests};
|
||||
use crate::{ReplayError, SessionsMock};
|
||||
use nym_kkt_ciphersuite::{IntoEnumIterator, KEM};
|
||||
|
||||
#[test]
|
||||
@@ -351,17 +357,17 @@ mod tests {
|
||||
let mut session = SessionsMock::mock_post_handshake(kem).responder;
|
||||
|
||||
// Initial stats
|
||||
let (next, received) = session.current_packet_cnt();
|
||||
assert_eq!(next, 0);
|
||||
assert_eq!(received, 0);
|
||||
let packet_count = session.current_packet_cnt();
|
||||
assert_eq!(packet_count.next, 0);
|
||||
assert_eq!(packet_count.received, 0);
|
||||
|
||||
// After receiving packets
|
||||
assert!(session.receiving_counter_mark(0).is_ok());
|
||||
assert!(session.receiving_counter_mark(1).is_ok());
|
||||
|
||||
let (next, received) = session.current_packet_cnt();
|
||||
assert_eq!(next, 2);
|
||||
assert_eq!(received, 2);
|
||||
let packet_count = session.current_packet_cnt();
|
||||
assert_eq!(packet_count.next, 2);
|
||||
assert_eq!(packet_count.received, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,10 +7,13 @@
|
||||
//! creation, retrieval, and storage of sessions.
|
||||
|
||||
use crate::session::SessionId;
|
||||
use crate::state_machine::{LpAction, LpInput, LpStateBare};
|
||||
use crate::state_machine::{LpAction, LpData, LpInput, LpStateBare};
|
||||
use crate::{LpError, LpSession, LpStateMachine};
|
||||
use nym_lp_packet::EncryptedLpPacket;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub use crate::replay::validator::PacketCount;
|
||||
|
||||
/// Manages the lifecycle of Lewes Protocol sessions.
|
||||
///
|
||||
/// The SessionManager is responsible for creating, storing, and retrieving sessions
|
||||
@@ -41,6 +44,19 @@ impl SessionManager {
|
||||
self.with_state_machine_mut(lp_id, |sm| sm.process_input(input).transpose())?
|
||||
}
|
||||
|
||||
pub fn send_data(&mut self, lp_id: SessionId, data: LpData) -> Result<LpAction, LpError> {
|
||||
self.process_input(lp_id, LpInput::SendData(data))?
|
||||
.ok_or(LpError::NotInTransport)
|
||||
}
|
||||
|
||||
pub fn receive_packet(
|
||||
&mut self,
|
||||
lp_id: SessionId,
|
||||
packet: EncryptedLpPacket,
|
||||
) -> Result<Option<LpAction>, LpError> {
|
||||
self.process_input(lp_id, LpInput::ReceivePacket(packet))
|
||||
}
|
||||
|
||||
pub fn closed(&self, lp_id: SessionId) -> Result<bool, LpError> {
|
||||
Ok(self.get_state(lp_id)? == LpStateBare::Closed)
|
||||
}
|
||||
@@ -58,31 +74,7 @@ impl SessionManager {
|
||||
self.with_state_machine(lp_id, |sm| Ok(sm.bare_state()))?
|
||||
}
|
||||
|
||||
pub fn receiving_counter_quick_check(
|
||||
&self,
|
||||
lp_id: SessionId,
|
||||
counter: u64,
|
||||
) -> Result<(), LpError> {
|
||||
self.with_state_machine(lp_id, |sm| {
|
||||
sm.session()?.receiving_counter_quick_check(counter)
|
||||
})?
|
||||
}
|
||||
|
||||
pub fn receiving_counter_mark(
|
||||
&mut self,
|
||||
lp_id: SessionId,
|
||||
counter: u64,
|
||||
) -> Result<(), LpError> {
|
||||
self.with_state_machine_mut(lp_id, |sm| {
|
||||
sm.session_mut()?.receiving_counter_mark(counter)
|
||||
})?
|
||||
}
|
||||
|
||||
pub fn next_counter(&mut self, lp_id: SessionId) -> Result<u64, LpError> {
|
||||
self.with_state_machine_mut(lp_id, |sm| Ok(sm.session_mut()?.next_counter()))?
|
||||
}
|
||||
|
||||
pub fn current_packet_cnt(&self, lp_id: SessionId) -> Result<(u64, u64), LpError> {
|
||||
pub fn current_packet_cnt(&self, lp_id: SessionId) -> Result<PacketCount, LpError> {
|
||||
self.with_state_machine(lp_id, |sm| Ok(sm.session()?.current_packet_cnt()))?
|
||||
}
|
||||
|
||||
@@ -117,11 +109,19 @@ impl SessionManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_session_state_machine(&mut self, lp_session: LpSession) -> SessionId {
|
||||
pub fn create_session_state_machine(
|
||||
&mut self,
|
||||
lp_session: LpSession,
|
||||
) -> Result<SessionId, LpError> {
|
||||
let session_id = *lp_session.session_identifier();
|
||||
|
||||
if self.state_machines.contains_key(&session_id) {
|
||||
return Err(LpError::DuplicateSessionId(session_id));
|
||||
}
|
||||
|
||||
let sm = LpStateMachine::new(lp_session);
|
||||
self.state_machines.insert(session_id, sm);
|
||||
session_id
|
||||
Ok(session_id)
|
||||
}
|
||||
|
||||
/// Method to remove a state machine
|
||||
@@ -144,7 +144,7 @@ mod tests {
|
||||
let local_session = mock_session_for_test();
|
||||
let id = *local_session.session_identifier();
|
||||
|
||||
let sm_1_id = manager.create_session_state_machine(local_session);
|
||||
let sm_1_id = manager.create_session_state_machine(local_session).unwrap();
|
||||
assert_eq!(sm_1_id, id);
|
||||
|
||||
let retrieved = manager.state_machine_exists(&id);
|
||||
@@ -158,7 +158,7 @@ mod tests {
|
||||
fn test_session_manager_remove() {
|
||||
let mut manager = SessionManager::new();
|
||||
let local_session = mock_session_for_test();
|
||||
let sm_1_id = manager.create_session_state_machine(local_session);
|
||||
let sm_1_id = manager.create_session_state_machine(local_session).unwrap();
|
||||
|
||||
let removed = manager.remove_state_machine(sm_1_id);
|
||||
assert!(removed);
|
||||
@@ -176,9 +176,9 @@ mod tests {
|
||||
let session2 = SessionsMock::mock_seeded_post_handshake(124, kem).initiator;
|
||||
let session3 = SessionsMock::mock_seeded_post_handshake(125, kem).initiator;
|
||||
|
||||
let sm_1 = manager.create_session_state_machine(session1);
|
||||
let sm_2 = manager.create_session_state_machine(session2);
|
||||
let sm_3 = manager.create_session_state_machine(session3);
|
||||
let sm_1 = manager.create_session_state_machine(session1).unwrap();
|
||||
let sm_2 = manager.create_session_state_machine(session2).unwrap();
|
||||
let sm_3 = manager.create_session_state_machine(session3).unwrap();
|
||||
|
||||
assert_eq!(manager.session_count(), 3);
|
||||
|
||||
@@ -198,7 +198,7 @@ mod tests {
|
||||
|
||||
let sesion = mock_session_for_test();
|
||||
|
||||
let sm = manager.create_session_state_machine(sesion);
|
||||
let sm = manager.create_session_state_machine(sesion).unwrap();
|
||||
assert_eq!(manager.session_count(), 1);
|
||||
|
||||
let retrieved = manager.get_state_machine_id(sm);
|
||||
|
||||
@@ -2,14 +2,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
//! Lewes Protocol State Machine for managing connection lifecycle.
|
||||
//!
|
||||
//! LP protocol flow (KKT → PSQ → Noise):
|
||||
//! 1. KKTExchange: Client requests gateway's KEM public key (signed for MITM protection)
|
||||
//! 2. Handshaking: Noise XKpsk3 with PSQ-derived PSK embedded in handshake messages
|
||||
//! - PSQ ciphertext piggybacked on ClientHello (no extra round-trip)
|
||||
//! - PSK = Blake3(ECDH || PSQ_secret || salt) provides hybrid classical+PQ security
|
||||
//! 3. Transport: ChaCha20-Poly1305 authenticated encryption with derived keys
|
||||
//!
|
||||
//! State machine ensures protocol steps execute in correct order. Invalid transitions
|
||||
//! return LpError, preventing protocol violations.
|
||||
|
||||
@@ -190,11 +182,6 @@ impl LpStateMachine {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> Result<u32, LpError> {
|
||||
todo!()
|
||||
// Ok(self.session()?.id())
|
||||
}
|
||||
|
||||
pub fn session_identifier(&self) -> Result<SessionId, LpError> {
|
||||
Ok(*self.session()?.session_identifier())
|
||||
}
|
||||
@@ -217,7 +204,7 @@ impl LpStateMachine {
|
||||
match input {
|
||||
LpInput::ReceivePacket(packet) => {
|
||||
// Check if packet lp_id matches our session
|
||||
if packet.outer_header().receiver_idx != session.id() {
|
||||
if packet.outer_header().receiver_idx != session.receiver_index() {
|
||||
let result_action = Some(Err(LpError::UnknownSessionId(
|
||||
packet.outer_header().receiver_idx,
|
||||
)));
|
||||
@@ -231,17 +218,17 @@ impl LpStateMachine {
|
||||
return (LpState::Transport(state), Some(Err(e)));
|
||||
}
|
||||
|
||||
// 2. Mark counter as received
|
||||
if let Err(e) = session.receiving_counter_mark(ctr) {
|
||||
return (LpState::Transport(state), Some(Err(e)));
|
||||
}
|
||||
|
||||
// 3. decrypt the packet and attempt to deliver data
|
||||
// 2. decrypt the packet and attempt to deliver data
|
||||
let packet = match session.decrypt_packet(packet) {
|
||||
Ok(packet) => packet,
|
||||
Err(e) => return (LpState::Transport(state), Some(Err(e))),
|
||||
};
|
||||
|
||||
// 3. Mark counter as received
|
||||
if let Err(e) = session.receiving_counter_mark(ctr) {
|
||||
return (LpState::Transport(state), Some(Err(e)));
|
||||
}
|
||||
|
||||
// Check message type
|
||||
match packet.into_message() {
|
||||
// Normal encrypted data
|
||||
@@ -373,77 +360,79 @@ mod tests {
|
||||
let resp_session = responder_sm.session().unwrap();
|
||||
|
||||
// Check both state machines use the same receiver_index
|
||||
assert_eq!(init_session.id(), resp_session.id());
|
||||
assert_eq!(init_session.receiver_index(), resp_session.receiver_index());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_state_machine_simplified_flow() {
|
||||
todo!()
|
||||
// for kem in KEM::iter() {
|
||||
// let receiver_index: u32 = 123;
|
||||
// let mock_sessions = SessionsMock::mock_post_handshake(kem);
|
||||
//
|
||||
// // Create state machines (already in Transport)
|
||||
// let mut initiator = LpStateMachine::new(mock_sessions.initiator);
|
||||
// let mut responder = LpStateMachine::new(mock_sessions.responder);
|
||||
//
|
||||
// assert_eq!(initiator.id().unwrap(), responder.id().unwrap());
|
||||
//
|
||||
// // --- Transport Phase ---
|
||||
// println!("--- Step 1: Initiator sends data ---");
|
||||
// let data_to_send_1 = LpData::new_opaque(b"hello responder".to_vec());
|
||||
// let init_actions_4 = initiator.process_input(LpInput::SendData(data_to_send_1.clone()));
|
||||
// let data_packet_1 = if let Some(Ok(LpAction::SendPacket(packet))) = init_actions_4 {
|
||||
// packet.clone()
|
||||
// } else {
|
||||
// panic!("Initiator should send data packet");
|
||||
// };
|
||||
// assert_eq!(data_packet_1.header.receiver_idx(), receiver_index);
|
||||
//
|
||||
// println!("--- Step 2: Responder receives data ---");
|
||||
// let resp_actions_5 = responder.process_input(LpInput::ReceivePacket(data_packet_1));
|
||||
// let resp_data_1 = if let Some(Ok(LpAction::DeliverData(data))) = resp_actions_5 {
|
||||
// data
|
||||
// } else {
|
||||
// panic!("Responder should deliver data");
|
||||
// };
|
||||
// assert_eq!(resp_data_1, data_to_send_1);
|
||||
//
|
||||
// println!("--- Step 3: Responder sends data ---");
|
||||
// let data_to_send_2 = LpData::new_opaque(b"hello initiator".to_vec());
|
||||
// let resp_actions_6 = responder.process_input(LpInput::SendData(data_to_send_2.clone()));
|
||||
// let data_packet_2 = if let Some(Ok(LpAction::SendPacket(packet))) = resp_actions_6 {
|
||||
// packet.clone()
|
||||
// } else {
|
||||
// panic!("Responder should send data packet");
|
||||
// };
|
||||
// assert_eq!(data_packet_2.header.receiver_idx(), receiver_index);
|
||||
//
|
||||
// println!("--- Step 4: Initiator receives data ---");
|
||||
// let init_actions_5 = initiator.process_input(LpInput::ReceivePacket(data_packet_2));
|
||||
// if let Some(Ok(LpAction::DeliverData(data))) = init_actions_5 {
|
||||
// assert_eq!(data, data_to_send_2);
|
||||
// } else {
|
||||
// panic!("Initiator should deliver data");
|
||||
// }
|
||||
//
|
||||
// // --- Close ---
|
||||
// println!("--- Step 5: Initiator closes ---");
|
||||
// let init_actions_6 = initiator.process_input(LpInput::Close);
|
||||
// assert!(matches!(
|
||||
// init_actions_6,
|
||||
// Some(Ok(LpAction::ConnectionClosed))
|
||||
// ));
|
||||
// assert!(matches!(initiator.state, LpState::Closed { .. }));
|
||||
//
|
||||
// println!("--- Step 6: Responder closes ---");
|
||||
// let resp_actions_7 = responder.process_input(LpInput::Close);
|
||||
// assert!(matches!(
|
||||
// resp_actions_7,
|
||||
// Some(Ok(LpAction::ConnectionClosed))
|
||||
// ));
|
||||
// assert!(matches!(responder.state, LpState::Closed { .. }));
|
||||
// }
|
||||
for kem in KEM::iter() {
|
||||
let mock_sessions = SessionsMock::mock_post_handshake(kem);
|
||||
let receiver_index = mock_sessions.responder.receiver_index();
|
||||
|
||||
// Create state machines (already in Transport)
|
||||
let mut initiator = LpStateMachine::new(mock_sessions.initiator);
|
||||
let mut responder = LpStateMachine::new(mock_sessions.responder);
|
||||
|
||||
assert_eq!(
|
||||
initiator.session_identifier().unwrap(),
|
||||
responder.session_identifier().unwrap()
|
||||
);
|
||||
|
||||
// --- Transport Phase ---
|
||||
println!("--- Step 1: Initiator sends data ---");
|
||||
let data_to_send_1 = LpData::new_opaque(b"hello responder".to_vec());
|
||||
let init_actions_4 = initiator.process_input(LpInput::SendData(data_to_send_1.clone()));
|
||||
let data_packet_1 = if let Some(Ok(LpAction::SendPacket(packet))) = init_actions_4 {
|
||||
packet.clone()
|
||||
} else {
|
||||
panic!("Initiator should send data packet");
|
||||
};
|
||||
assert_eq!(data_packet_1.outer_header().receiver_idx, receiver_index);
|
||||
|
||||
println!("--- Step 2: Responder receives data ---");
|
||||
let resp_actions_5 = responder.process_input(LpInput::ReceivePacket(data_packet_1));
|
||||
let resp_data_1 = if let Some(Ok(LpAction::DeliverData(data))) = resp_actions_5 {
|
||||
data
|
||||
} else {
|
||||
panic!("Responder should deliver data");
|
||||
};
|
||||
assert_eq!(resp_data_1, data_to_send_1);
|
||||
|
||||
println!("--- Step 3: Responder sends data ---");
|
||||
let data_to_send_2 = LpData::new_opaque(b"hello initiator".to_vec());
|
||||
let resp_actions_6 = responder.process_input(LpInput::SendData(data_to_send_2.clone()));
|
||||
let data_packet_2 = if let Some(Ok(LpAction::SendPacket(packet))) = resp_actions_6 {
|
||||
packet.clone()
|
||||
} else {
|
||||
panic!("Responder should send data packet");
|
||||
};
|
||||
assert_eq!(data_packet_2.outer_header().receiver_idx, receiver_index);
|
||||
|
||||
println!("--- Step 4: Initiator receives data ---");
|
||||
let init_actions_5 = initiator.process_input(LpInput::ReceivePacket(data_packet_2));
|
||||
if let Some(Ok(LpAction::DeliverData(data))) = init_actions_5 {
|
||||
assert_eq!(data, data_to_send_2);
|
||||
} else {
|
||||
panic!("Initiator should deliver data");
|
||||
}
|
||||
|
||||
// --- Close ---
|
||||
println!("--- Step 5: Initiator closes ---");
|
||||
let init_actions_6 = initiator.process_input(LpInput::Close);
|
||||
assert!(matches!(
|
||||
init_actions_6,
|
||||
Some(Ok(LpAction::ConnectionClosed))
|
||||
));
|
||||
assert!(matches!(initiator.state, LpState::Closed { .. }));
|
||||
|
||||
println!("--- Step 6: Responder closes ---");
|
||||
let resp_actions_7 = responder.process_input(LpInput::Close);
|
||||
assert!(matches!(
|
||||
resp_actions_7,
|
||||
Some(Ok(LpAction::ConnectionClosed))
|
||||
));
|
||||
assert!(matches!(responder.state, LpState::Closed { .. }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use nym_authenticator_requests::AuthenticatorVersion;
|
||||
use nym_crypto::asymmetric::x25519::serde_helpers::bs58_x25519_pubkey;
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_ip_packet_requests::IpPair;
|
||||
use nym_kkt_ciphersuite::{Ciphersuite, KEM, KEMKeyDigests, SignatureScheme};
|
||||
use nym_kkt_ciphersuite::{Ciphersuite, KEM, KEMKeyDigests};
|
||||
use nym_sphinx::addressing::Recipient;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -162,7 +162,7 @@ where
|
||||
}
|
||||
Ok(Ok(session)) => session,
|
||||
};
|
||||
let receiver_idx = session.id();
|
||||
let receiver_idx = session.receiver_index();
|
||||
|
||||
// 2. insert the state machine into the shared state
|
||||
let state_machine = LpStateMachine::new(session);
|
||||
@@ -742,7 +742,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn add_dummy_lp_state(handler: &mut LpConnectionHandler, session: LpSession) {
|
||||
let id = session.id();
|
||||
let id = session.receiver_index();
|
||||
let state_machine = LpStateMachine::new(session);
|
||||
handler.bound_receiver_idx = Some(id);
|
||||
|
||||
|
||||
@@ -398,112 +398,115 @@ mod tests {
|
||||
#[cfg(test)]
|
||||
mod using_lp_registration_client {
|
||||
use super::*;
|
||||
use nym_kkt_ciphersuite::{IntoEnumIterator, KEM};
|
||||
use nym_registration_client::NestedLpSession;
|
||||
use nym_test_utils::helpers::u64_seeded_rng_09;
|
||||
use nym_wireguard::DefguardPeer;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_basic_lp_entry_registration() -> anyhow::Result<()> {
|
||||
let TODO = "test with different kems";
|
||||
let ciphersuite = Ciphersuite::default();
|
||||
for kem in KEM::iter() {
|
||||
let ciphersuite = Ciphersuite::default().with_kem(kem);
|
||||
|
||||
// nym_test_utils::helpers::setup_test_logger();
|
||||
// initialise random, but deterministic, keys, addresses, etc. for the parties
|
||||
let mut client_rng = u64_seeded_rng_09(0);
|
||||
let mut gateway_rng = u64_seeded_rng_09(1);
|
||||
// nym_test_utils::helpers::setup_test_logger();
|
||||
// initialise random, but deterministic, keys, addresses, etc. for the parties
|
||||
let mut client_rng = u64_seeded_rng_09(0);
|
||||
let mut gateway_rng = u64_seeded_rng_09(1);
|
||||
|
||||
let client_data = Client::mock(&mut client_rng);
|
||||
let client_key = *client_data.base.x25519_wg_keys.public_key();
|
||||
let mut entry = Gateway::mock(&mut gateway_rng).await?;
|
||||
let client_data = Client::mock(&mut client_rng);
|
||||
let client_key = *client_data.base.x25519_wg_keys.public_key();
|
||||
let mut entry = Gateway::mock(&mut gateway_rng).await?;
|
||||
|
||||
let mut client = LpRegistrationClient::<MockIOStream>::new_with_default_config(
|
||||
client_data.base.peer.x25519().clone(),
|
||||
entry.base.peer.as_remote(),
|
||||
entry.base.socket_addr,
|
||||
ciphersuite,
|
||||
entry.base.lp_version,
|
||||
);
|
||||
let mut client = LpRegistrationClient::<MockIOStream>::new_with_default_config(
|
||||
client_data.base.peer.x25519().clone(),
|
||||
entry.base.peer.as_remote(),
|
||||
entry.base.socket_addr,
|
||||
ciphersuite,
|
||||
entry.base.lp_version,
|
||||
);
|
||||
|
||||
// 1. establish mock connection between client and gateway and retrieve gateway's handle
|
||||
client.ensure_connected().await?;
|
||||
let gateway_conn = client
|
||||
.connection()
|
||||
.as_ref()
|
||||
.context("mock connection has failed!")?
|
||||
.try_get_remote_handle();
|
||||
// 1. establish mock connection between client and gateway and retrieve gateway's handle
|
||||
client.ensure_connected().await?;
|
||||
let gateway_conn = client
|
||||
.connection()
|
||||
.as_ref()
|
||||
.context("mock connection has failed!")?
|
||||
.try_get_remote_handle();
|
||||
|
||||
// 2. create and spawn gateway handler for the client connection
|
||||
entry.create_lp_handler(gateway_conn, client_data.base.socket_addr);
|
||||
entry.spawn_lp_handler();
|
||||
// 2. create and spawn gateway handler for the client connection
|
||||
entry.create_lp_handler(gateway_conn, client_data.base.socket_addr);
|
||||
entry.spawn_lp_handler();
|
||||
|
||||
// 3. register all needed responses for the dvpn registration that will reach the peer controller
|
||||
// 1) peer registration - ip pair allocation
|
||||
let ip_pair = entry.pre_allocate_ip_pair();
|
||||
let reg_res = Ok::<_, nym_wireguard::Error>(ip_pair);
|
||||
// 3. register all needed responses for the dvpn registration that will reach the peer controller
|
||||
// 1) peer registration - ip pair allocation
|
||||
let ip_pair = entry.pre_allocate_ip_pair();
|
||||
let reg_res = Ok::<_, nym_wireguard::Error>(ip_pair);
|
||||
|
||||
entry
|
||||
.register_peer_controller_response(
|
||||
PeerControlRequestType::AllocatePeerIpPair {},
|
||||
reg_res,
|
||||
)
|
||||
.await;
|
||||
entry
|
||||
.register_peer_controller_response(
|
||||
PeerControlRequestType::AllocatePeerIpPair {},
|
||||
reg_res,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 2) new peer inclusion - in non-mock system it would spawn handlers,
|
||||
// here we'll just set a flag and say it's all fine
|
||||
let public_key = client_key.to_wg_key();
|
||||
let add_res = Ok::<_, nym_wireguard::Error>(());
|
||||
entry
|
||||
.register_peer_controller_response(
|
||||
PeerControlRequestType::AddPeer { public_key },
|
||||
add_res,
|
||||
)
|
||||
.await;
|
||||
// 2) new peer inclusion - in non-mock system it would spawn handlers,
|
||||
// here we'll just set a flag and say it's all fine
|
||||
let public_key = client_key.to_wg_key();
|
||||
let add_res = Ok::<_, nym_wireguard::Error>(());
|
||||
entry
|
||||
.register_peer_controller_response(
|
||||
PeerControlRequestType::AddPeer { public_key },
|
||||
add_res,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 3) peer query - check for prior registrations
|
||||
let query_res = Ok::<_, nym_wireguard::Error>(Option::<DefguardPeer>::None);
|
||||
let key = client_key.to_wg_key();
|
||||
entry
|
||||
.register_peer_controller_response(
|
||||
PeerControlRequestType::QueryPeer { key },
|
||||
query_res,
|
||||
)
|
||||
.await;
|
||||
// 3) peer query - check for prior registrations
|
||||
let query_res = Ok::<_, nym_wireguard::Error>(Option::<DefguardPeer>::None);
|
||||
let key = client_key.to_wg_key();
|
||||
entry
|
||||
.register_peer_controller_response(
|
||||
PeerControlRequestType::QueryPeer { key },
|
||||
query_res,
|
||||
)
|
||||
.await;
|
||||
|
||||
// 4. spawn peer controller to be able to handle dvpn registration requests
|
||||
entry.spawn_peer_controller();
|
||||
// 4. spawn peer controller to be able to handle dvpn registration requests
|
||||
entry.spawn_peer_controller();
|
||||
|
||||
// 5. perform client handshake
|
||||
client.perform_handshake().timeboxed().await??;
|
||||
// 5. perform client handshake
|
||||
client.perform_handshake().timeboxed().await??;
|
||||
|
||||
// 6. perform registration with entry only
|
||||
let wg_keypair = client_data.base.x25519_wg_keys;
|
||||
let gateway_identity = entry.base.identity.public_key();
|
||||
let registration_result = client
|
||||
.register_dvpn(
|
||||
&mut client_rng,
|
||||
&wg_keypair,
|
||||
gateway_identity,
|
||||
&client_data.ticket_provider,
|
||||
TicketType::V1WireguardEntry,
|
||||
)
|
||||
.timeboxed()
|
||||
.await??;
|
||||
// 6. perform registration with entry only
|
||||
let wg_keypair = client_data.base.x25519_wg_keys;
|
||||
let gateway_identity = entry.base.identity.public_key();
|
||||
let registration_result = client
|
||||
.register_dvpn(
|
||||
&mut client_rng,
|
||||
&wg_keypair,
|
||||
gateway_identity,
|
||||
&client_data.ticket_provider,
|
||||
TicketType::V1WireguardEntry,
|
||||
)
|
||||
.timeboxed()
|
||||
.await??;
|
||||
|
||||
// 7. verify registration result
|
||||
let peers_guard = entry.mock_peer_controller_state.peers.read().await;
|
||||
let peer = peers_guard.get_by_x25519_key(&client_key).unwrap().clone();
|
||||
drop(peers_guard);
|
||||
assert!(peer.add_success);
|
||||
// 7. verify registration result
|
||||
let peers_guard = entry.mock_peer_controller_state.peers.read().await;
|
||||
let peer = peers_guard.get_by_x25519_key(&client_key).unwrap().clone();
|
||||
drop(peers_guard);
|
||||
assert!(peer.add_success);
|
||||
|
||||
assert_eq!(registration_result.private_ipv4, ip_pair.ipv4);
|
||||
assert_eq!(registration_result.private_ipv6, ip_pair.ipv6);
|
||||
assert_eq!(
|
||||
registration_result.public_key,
|
||||
*entry.base.x25519_wg_keys.public_key()
|
||||
);
|
||||
assert_eq!(registration_result.private_ipv4, ip_pair.ipv4);
|
||||
assert_eq!(registration_result.private_ipv6, ip_pair.ipv6);
|
||||
assert_eq!(
|
||||
registration_result.public_key,
|
||||
*entry.base.x25519_wg_keys.public_key()
|
||||
);
|
||||
|
||||
// 8. stop the gateway task and finish the test
|
||||
entry.stop_tasks().await?;
|
||||
}
|
||||
|
||||
// 8. stop the gateway task and finish the test
|
||||
entry.stop_tasks().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -570,7 +573,7 @@ mod tests {
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_basic_lp_exit_registration() -> anyhow::Result<()> {
|
||||
nym_test_utils::helpers::setup_test_logger();
|
||||
// nym_test_utils::helpers::setup_test_logger();
|
||||
|
||||
let TODO = "test with different kems";
|
||||
let ciphersuite = Ciphersuite::default();
|
||||
@@ -705,7 +708,6 @@ mod tests {
|
||||
let mut nested_session = NestedLpSession::new(
|
||||
exit.base.socket_addr,
|
||||
client_data.base.peer.x25519().clone(),
|
||||
*exit.base.identity.public_key(),
|
||||
exit.base.peer.as_remote(),
|
||||
ciphersuite,
|
||||
exit.base.lp_version,
|
||||
|
||||
@@ -60,8 +60,6 @@ impl LpBasedRegistrationClient {
|
||||
let entry_address = entry_lp_data.address;
|
||||
let exit_address = exit_lp_data.address;
|
||||
|
||||
let exit_identity = self.config.exit.node.identity;
|
||||
|
||||
tracing::debug!("Entry gateway LP address: {entry_address}");
|
||||
tracing::debug!("Exit gateway LP address: {exit_address}");
|
||||
|
||||
@@ -103,7 +101,6 @@ impl LpBasedRegistrationClient {
|
||||
let mut nested_session = NestedLpSession::new(
|
||||
exit_address,
|
||||
exit_lp_keypair,
|
||||
exit_identity,
|
||||
exit_peer,
|
||||
exit_ciphersuite,
|
||||
exit_lp_protocol,
|
||||
|
||||
@@ -5,20 +5,16 @@
|
||||
|
||||
use super::config::LpRegistrationConfig;
|
||||
use super::error::{LpClientError, Result};
|
||||
use crate::lp_client::helpers::{
|
||||
LpDataDeliverExt, LpDataSendExt, convert_forward_data, try_convert_forward_response,
|
||||
};
|
||||
use crate::lp_client::helpers::{LpDataDeliverExt, LpDataSendExt};
|
||||
use crate::lp_client::nested_session::connection::NestedConnection;
|
||||
use crate::lp_client::state_machine_helpers::{extract_forwarded_response, prepare_send_packet};
|
||||
use bytes::BytesMut;
|
||||
use futures::SinkExt;
|
||||
use nym_bandwidth_controller::{BandwidthTicketProvider, DEFAULT_TICKETS_TO_SPEND};
|
||||
use nym_credentials_interface::TicketType;
|
||||
use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_lp::LpSession;
|
||||
use nym_lp::peer::{DHKeyPair, LpLocalPeer, LpRemotePeer};
|
||||
use nym_lp::state_machine::{LpAction, LpData, LpInput, LpStateMachine};
|
||||
use nym_lp::{Ciphersuite, EncryptedLpPacket, ForwardPacketData, packet::version};
|
||||
use nym_lp::{LpPacket, LpSession};
|
||||
use nym_lp::state_machine::LpStateMachine;
|
||||
use nym_lp::{Ciphersuite, EncryptedLpPacket, packet::version};
|
||||
use nym_lp_transport::traits::LpTransportChannel;
|
||||
use nym_lp_transport::{LpHandshakeChannel, LpTransportError};
|
||||
use nym_registration_common::dvpn::LpDvpnRegistrationResponseMessageContent;
|
||||
@@ -120,13 +116,8 @@ where
|
||||
}
|
||||
|
||||
/// Attempt to use this `LpRegistrationClient` as transport for `NestedSession`
|
||||
pub fn as_nested_connection(
|
||||
&mut self,
|
||||
exit_identity: ed25519::PublicKey,
|
||||
exit_address: SocketAddr,
|
||||
) -> NestedConnection<'_, S> {
|
||||
pub fn as_nested_connection(&mut self, exit_address: SocketAddr) -> NestedConnection<'_, S> {
|
||||
NestedConnection {
|
||||
exit_identity,
|
||||
exit_address,
|
||||
outer_client: self,
|
||||
}
|
||||
@@ -723,7 +714,7 @@ where
|
||||
pub fn session_id(&self) -> Result<u32> {
|
||||
self.state_machine()?
|
||||
.session()
|
||||
.map(|s| s.id())
|
||||
.map(|s| s.receiver_index())
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
use nym_lp::state_machine::{LpAction, LpDataKind};
|
||||
use nym_lp::{LpError, MalformedLpPacketError};
|
||||
use nym_lp_transport::LpTransportError;
|
||||
use nym_registration_common::BincodeError;
|
||||
use std::time::Duration;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Errors that can occur during LP client operations.
|
||||
@@ -74,49 +72,6 @@ pub enum LpClientError {
|
||||
|
||||
#[error("{0}")]
|
||||
Other(String),
|
||||
// /// Failed to send registration request
|
||||
// #[error("Failed to send registration request: {0}")]
|
||||
// SendRegistrationRequest(String),
|
||||
//
|
||||
// /// Failed to receive registration response
|
||||
// #[error("Failed to receive registration response: {0}")]
|
||||
// ReceiveRegistrationResponse(String),
|
||||
//
|
||||
// /// Registration was rejected by gateway
|
||||
// #[error("Gateway rejected registration: {reason}")]
|
||||
// RegistrationRejected { reason: String },
|
||||
//
|
||||
// /// Failed to receive response within specified deadline
|
||||
// #[error("Failed to receive response within the set timeout: {timeout:?}")]
|
||||
// ResponseReceiveTimeout { timeout: Duration },
|
||||
//
|
||||
// /// LP transport error
|
||||
// #[error("LP transport error: {0}")]
|
||||
// Transport(String),
|
||||
//
|
||||
// #[error(transparent)]
|
||||
// LpTransportError(#[from] LpTransportError),
|
||||
//
|
||||
// /// Invalid LP address format
|
||||
// #[error("Invalid LP address '{address}': {reason}")]
|
||||
// InvalidAddress { address: String, reason: String },
|
||||
//
|
||||
// /// Serialization/deserialization error
|
||||
// #[error("Serialization error: {0}")]
|
||||
// Serialization(#[from] BincodeError),
|
||||
//
|
||||
// /// Connection closed unexpectedly
|
||||
// #[error("Connection closed unexpectedly")]
|
||||
// ConnectionClosed,
|
||||
//
|
||||
// /// Timeout waiting for response
|
||||
// #[error("Timeout waiting for {operation}")]
|
||||
// Timeout { operation: String },
|
||||
|
||||
//
|
||||
// /// Another uncategorized error
|
||||
// #[error("{0}")]
|
||||
// Other(String),
|
||||
}
|
||||
|
||||
impl LpClientError {
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use crate::LpClientError;
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_lp::ForwardPacketData;
|
||||
use nym_lp::peer::LpRemotePeer;
|
||||
use nym_lp::state_machine::{LpAction, LpData, LpDataKind, LpInput};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use crate::lp_client::helpers::{convert_forward_data, try_convert_forward_response};
|
||||
use crate::{LpClientError, LpRegistrationClient};
|
||||
use bytes::{BufMut, BytesMut};
|
||||
use nym_crypto::asymmetric::ed25519;
|
||||
use nym_lp::state_machine::{LpAction, LpInput};
|
||||
use nym_lp::{EncryptedLpPacket, ExpectedResponseSize, ForwardPacketData, KEM};
|
||||
use nym_lp_transport::traits::{HandshakeMessage, LpTransportChannel};
|
||||
@@ -14,9 +13,6 @@ use std::net::SocketAddr;
|
||||
|
||||
/// Attempt to treat the inner client as a LP connection
|
||||
pub struct NestedConnection<'a, S> {
|
||||
/// Remote Ed25519 public key
|
||||
pub(crate) exit_identity: ed25519::PublicKey,
|
||||
|
||||
/// Exit gateway's LP address (e.g., "2.2.2.2:41264")
|
||||
pub(crate) exit_address: SocketAddr,
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ use nym_crypto::asymmetric::{ed25519, x25519};
|
||||
use nym_lp::packet::version;
|
||||
use nym_lp::peer::{DHKeyPair, LpLocalPeer, LpRemotePeer};
|
||||
use nym_lp::state_machine::{LpData, LpStateMachine};
|
||||
use nym_lp::{Ciphersuite, EncryptedLpPacket, ForwardPacketData, LpPacket, LpSession};
|
||||
use nym_lp::{Ciphersuite, EncryptedLpPacket, LpSession};
|
||||
use nym_lp_transport::LpHandshakeChannel;
|
||||
use nym_lp_transport::traits::LpTransportChannel;
|
||||
use nym_registration_common::dvpn::LpDvpnRegistrationResponseMessageContent;
|
||||
@@ -71,9 +71,6 @@ pub struct NestedLpSession {
|
||||
/// Encapsulates all the client keys needed for the Lewes Protocol.
|
||||
lp_local_peer: LpLocalPeer,
|
||||
|
||||
/// Identity of the exit gateway
|
||||
gateway_identity: ed25519::PublicKey,
|
||||
|
||||
/// Encapsulates all the exit gateway keys needed for the Lewes Protocol.
|
||||
gateway_lp_peer: LpRemotePeer,
|
||||
|
||||
@@ -97,7 +94,6 @@ impl NestedLpSession {
|
||||
pub fn new(
|
||||
exit_address: SocketAddr,
|
||||
client_keypair: Arc<DHKeyPair>,
|
||||
gateway_identity: ed25519::PublicKey,
|
||||
gateway_lp_peer: LpRemotePeer,
|
||||
ciphersuite: Ciphersuite,
|
||||
gateway_supported_lp_protocol_version: u8,
|
||||
@@ -117,19 +113,12 @@ impl NestedLpSession {
|
||||
Self {
|
||||
exit_address,
|
||||
lp_local_peer,
|
||||
gateway_identity,
|
||||
gateway_lp_peer,
|
||||
gateway_supported_lp_protocol_version: lp_protocol,
|
||||
state_machine: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn state_machine(&self) -> Result<&LpStateMachine> {
|
||||
self.state_machine
|
||||
.as_ref()
|
||||
.ok_or(LpClientError::IncompleteHandshake)
|
||||
}
|
||||
|
||||
fn state_machine_mut(&mut self) -> Result<&mut LpStateMachine> {
|
||||
self.state_machine
|
||||
.as_mut()
|
||||
@@ -178,8 +167,7 @@ impl NestedLpSession {
|
||||
self.exit_address
|
||||
);
|
||||
|
||||
let mut nested_connection =
|
||||
outer_client.as_nested_connection(self.gateway_identity, self.exit_address);
|
||||
let mut nested_connection = outer_client.as_nested_connection(self.exit_address);
|
||||
|
||||
let local_peer = self.lp_local_peer.clone();
|
||||
let remote_peer = self.gateway_lp_peer.clone();
|
||||
@@ -233,8 +221,7 @@ impl NestedLpSession {
|
||||
S: LpTransportChannel + LpHandshakeChannel + Unpin,
|
||||
{
|
||||
tracing::debug!("Acquiring bandwidth credential for registration");
|
||||
let mut nested_connection =
|
||||
outer_client.as_nested_connection(self.gateway_identity, self.exit_address);
|
||||
let mut nested_connection = outer_client.as_nested_connection(self.exit_address);
|
||||
|
||||
// Step 1: Get bandwidth credential from controller
|
||||
let credential_spending = bandwidth_controller
|
||||
@@ -341,8 +328,7 @@ impl NestedLpSession {
|
||||
S: LpTransportChannel + LpHandshakeChannel + Unpin,
|
||||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let mut nested_connection =
|
||||
outer_client.as_nested_connection(self.gateway_identity, self.exit_address);
|
||||
let mut nested_connection = outer_client.as_nested_connection(self.exit_address);
|
||||
|
||||
tracing::debug!("Building registration request for exit gateway");
|
||||
|
||||
@@ -441,8 +427,7 @@ impl NestedLpSession {
|
||||
/// - Forwarding through entry gateway fails
|
||||
/// - Response decryption/deserialization fails
|
||||
/// - Gateway rejects the registration
|
||||
#[deprecated(note = "use explicit handshake and register methods")]
|
||||
pub async fn handshake_and_register_dvpn<S, R>(
|
||||
pub(crate) async fn handshake_and_register_dvpn<S, R>(
|
||||
&mut self,
|
||||
outer_client: &mut LpRegistrationClient<S>,
|
||||
rng: &mut R,
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
use crate::LpClientError;
|
||||
use nym_lp::state_machine::{LpAction, LpData, LpInput};
|
||||
use nym_lp::{EncryptedLpPacket, LpPacket, LpStateMachine};
|
||||
use nym_lp::{EncryptedLpPacket, LpStateMachine};
|
||||
|
||||
/// Attempt to prepare the provided data for sending by wrapping it in appropriate `LpAction`,
|
||||
/// and attempting to extract `EncryptedLpPacket` from the provided state machine.
|
||||
|
||||
Reference in New Issue
Block a user