diff --git a/reference/examples/extensive_test.rs b/reference/examples/extensive_test.rs index cd33ea8..a568fe7 100644 --- a/reference/examples/extensive_test.rs +++ b/reference/examples/extensive_test.rs @@ -65,9 +65,7 @@ impl CryptoLayer for TestApplication { type SessionData = u128; } #[allow(unused)] -impl ApplicationLayer for &mut TestApplication { - type Crypto = TestApplication; - +impl ApplicationLayer for &mut TestApplication { fn hello_requires_recognized_ratchet(&mut self) -> bool { false } diff --git a/reference/examples/ping_pong.rs b/reference/examples/ping_pong.rs index 671be5a..cb007d7 100644 --- a/reference/examples/ping_pong.rs +++ b/reference/examples/ping_pong.rs @@ -44,9 +44,7 @@ impl CryptoLayer for MyApp { /// In this example for simplicity we won't be hooking up ratchet keys to a filesystem backend. /// They are dropped and peers ignore if they are missing. #[allow(unused)] -impl ApplicationLayer for &mut MyApp { - type Crypto = MyApp; - +impl ApplicationLayer for &mut MyApp { fn hello_requires_recognized_ratchet(&mut self) -> bool { false } diff --git a/reference/src/application.rs b/reference/src/application.rs index 5ee301e..5758acc 100644 --- a/reference/src/application.rs +++ b/reference/src/application.rs @@ -139,10 +139,7 @@ pub trait CryptoLayer: Sized { /// /// Templating ZSSP on this trait lets the code here be almost entirely transport, OS, /// and use case independent. -pub trait ApplicationLayer: Sized { - /// Specifies which concrete set of cryptography types will be used by this application. - type Crypto: CryptoLayer; - +pub trait ApplicationLayer: Sized { /// Should return the current time in milliseconds. Does not have to be monotonic, nor synced /// with remote peers (although both of these properties would help reliability slightly). /// Used to determine if any current handshakes should be resent or timed-out, or if a session @@ -174,7 +171,7 @@ pub trait ApplicationLayer: Sized { /// least one party is misconfigured and got their ratchet keys corrupted or lost, or Bob has /// been compromised and is being impersonated. An attacker must at least have Bob's private /// static key to be able to ask Alice to downgrade. - fn initiator_disallows_downgrade(&mut self, session: &Arc>) -> bool; + fn initiator_disallows_downgrade(&mut self, session: &Arc>) -> bool; /// Function to accept sessions after final negotiation. /// The second argument is the identity that the remote peer sent us. The application /// must verify this identity is associated with the remote peer's static key. @@ -183,9 +180,9 @@ pub trait ApplicationLayer: Sized { /// before returning. fn check_accept_session( &mut self, - remote_static_key: &::PublicKey, + remote_static_key: &::PublicKey, identity: &[u8], - ) -> AcceptAction; + ) -> AcceptAction; /// Lookup a specific ratchet state based on its ratchet fingerprint. /// This function will be called whenever Alice attempts to connect to us with a non-empty @@ -213,8 +210,8 @@ pub trait ApplicationLayer: Sized { /// function `ApplicationLayer::check_accept_session`. fn restore_by_identity( &mut self, - remote_static_key: &::PublicKey, - session_data: &::SessionData, + remote_static_key: &::PublicKey, + session_data: &::SessionData, ) -> Result, std::io::Error>; /// Atomically commit the update specified by `update_data` to storage, or return an error if /// the update could not be made. @@ -234,8 +231,8 @@ pub trait ApplicationLayer: Sized { /// Otherwise, when we restart, we will not be allowed to reconnect. fn save_ratchet_state( &mut self, - remote_static_key: &::PublicKey, - session_data: &::SessionData, + remote_static_key: &::PublicKey, + session_data: &::SessionData, update_data: RatchetUpdate<'_>, ) -> Result<(), std::io::Error>; @@ -244,7 +241,7 @@ pub trait ApplicationLayer: Sized { /// nothing else. Do not base protocol-level decisions upon the events passed to this function. #[cfg(feature = "logging")] #[allow(unused)] - fn event_log(&mut self, event: LogEvent<'_, Self::Crypto>) {} + fn event_log(&mut self, event: LogEvent<'_, C>) {} } /// A collection of fields specifying how to complete the key exchange with a specific remote peer, diff --git a/reference/src/context.rs b/reference/src/context.rs index ca441f8..482705f 100644 --- a/reference/src/context.rs +++ b/reference/src/context.rs @@ -31,21 +31,21 @@ pub(crate) use log; /// defragment incoming packets that are not yet associated with a session. /// /// Internally this is just a clonable Arc, so it can be safely shared with multiple threads. -pub struct Context(Arc>); -impl Clone for Context { +pub struct Context(Arc>); +impl Clone for Context { fn clone(&self) -> Self { Self(self.0.clone()) } } -pub(crate) type SessionMap = RefCell>>>; +pub(crate) type SessionMap = RefCell>>>; -pub(crate) struct ContextInner { - pub(crate) rng: RefCell, - pub(crate) s_secret: Crypto::KeyPair, - pub(crate) session_map: SessionMap, - pub(crate) sessions: RefCell, Weak>>>, - pub(crate) b2_map: RefCell>>, +pub(crate) struct ContextInner { + pub(crate) rng: RefCell, + pub(crate) s_secret: C::KeyPair, + pub(crate) session_map: SessionMap, + pub(crate) sessions: RefCell, Weak>>>, + pub(crate) b2_map: RefCell>>, hello_defrag: RefCell, challenge: RefCell, @@ -62,9 +62,9 @@ fn to_packet_nonce(n: &[u8; AES_GCM_NONCE_SIZE]) -> &[u8; PACKET_NONCE_SIZE] { (&n[n.len() - PACKET_NONCE_SIZE..]).try_into().unwrap() } -impl Context { +impl Context { /// Create a new session context. - pub fn new(static_secret_key: Crypto::KeyPair, mut rng: Crypto::Rng) -> Self { + pub fn new(static_secret_key: C::KeyPair, mut rng: C::Rng) -> Self { let challenge = ChallengeContext::new(&mut rng); Self(Arc::new(ContextInner { rng: RefCell::new(rng), @@ -93,18 +93,15 @@ impl Context { /// object /// * `identity` - Payload to be sent to Bob that contains the information necessary /// for the upper protocol to authenticate and approve of Alice's identity - pub fn open( + pub fn open>( &mut self, app: App, send: impl FnMut(Vec) -> bool, mut mtu: usize, - static_remote_key: Crypto::PublicKey, - session_data: Crypto::SessionData, + static_remote_key: C::PublicKey, + session_data: C::SessionData, identity: Vec, - ) -> Result>, OpenError> - where - App: ApplicationLayer, - { + ) -> Result>, OpenError> { mtu = mtu.max(MIN_TRANSPORT_MTU); if identity.len() > IDENTITY_MAX_SIZE { return Err(OpenError::IdentityTooLarge); @@ -120,7 +117,7 @@ impl Context { identity, |Packet(kid, nonce, payload): &Packet| { // Process fragmentation layer. - let _ = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(&nonce), payload, None); + let _ = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(&nonce), payload, None); }, ) } @@ -133,18 +130,15 @@ impl Context { /// * `send_to` - Function to get senders for existing sessions, permitting MTU and path lookup /// * `remote_address` - Whatever the remote address is, as long as you can Hash it /// * `raw_fragment` - Buffer containing incoming wire packet - pub fn receive) -> bool>( + pub fn receive, SendFn: FnMut(Vec) -> bool>( &mut self, mut app: App, send_unassociated_reply: impl FnMut(Vec) -> bool, mut send_unassociated_mtu: usize, - send_to: impl FnOnce(&Arc>) -> Option<(SendFn, usize)>, + send_to: impl FnOnce(&Arc>) -> Option<(SendFn, usize)>, remote_address: &impl Hash, raw_fragment: Vec, - ) -> Result, ReceiveError> - where - App: ApplicationLayer, - { + ) -> Result, ReceiveError> { use crate::result::FaultType::*; send_unassociated_mtu = send_unassociated_mtu.max(MIN_TRANSPORT_MTU); let ctx = &self.0; @@ -158,7 +152,7 @@ impl Context { let mut zeta = session.0.borrow_mut(); let result = zeta.defrag - .received_fragment::(raw_fragment, app.time(), |n, frag_no, frag_count| { + .received_fragment::(raw_fragment, app.time(), |n, frag_no, frag_count| { let (p, c) = from_nonce(n); if p != PACKET_TYPE_DATA { log!(app, ReceivedRawFragment(p, c, frag_no, frag_count)); @@ -193,7 +187,7 @@ impl Context { |Packet(kid, nonce, payload): &Packet, hk: Option<&[u8; AES_256_KEY_SIZE]>| { if let Some((send_fragment, mut mtu)) = send_to(&session) { mtu = mtu.max(MIN_TRANSPORT_MTU); - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_fragment, mtu, *kid, @@ -207,7 +201,7 @@ impl Context { let (p, _) = from_nonce(&pn); let ret = match p { PACKET_TYPE_DATA => { - received_payload_in_place::( + received_payload_in_place::( &mut zeta, kid_recv, to_aes_nonce(&pn), @@ -297,7 +291,7 @@ impl Context { } PACKET_TYPE_SESSION_REJECTED => { log!(app, ReceivedRawD); - received_d_trans::(&mut zeta, kid_recv, to_aes_nonce(&pn), assembled_packet)?; + received_d_trans::(&mut zeta, kid_recv, to_aes_nonce(&pn), assembled_packet)?; log!(app, DIsAuthClosedSession(&session)); SessionEvent::Rejected } @@ -313,17 +307,19 @@ impl Context { if let Entry::Occupied(mut entry) = b2_map.entry(kid_recv) { let zeta = entry.get_mut(); // Process recv fragmentation layer. - let result = - zeta.defrag - .received_fragment::(raw_fragment, app.time(), |n, frag_no, frag_count| { - let (p, c) = from_nonce(n); - log!(app, ReceivedRawFragment(p, c, frag_no, frag_count)); - if p == PACKET_TYPE_HANDSHAKE_COMPLETION && c == 0 { - Ok(()) - } else { - Err(byzantine_fault!(InvalidPacket, true)) - } - })?; + let result = zeta.defrag.received_fragment::( + raw_fragment, + app.time(), + |n, frag_no, frag_count| { + let (p, c) = from_nonce(n); + log!(app, ReceivedRawFragment(p, c, frag_no, frag_count)); + if p == PACKET_TYPE_HANDSHAKE_COMPLETION && c == 0 { + Ok(()) + } else { + Err(byzantine_fault!(InvalidPacket, true)) + } + }, + )?; if let Some((_, assembled_packet)) = result { log!(app, ReceivedRawX3); let zeta = entry.remove(); @@ -334,7 +330,7 @@ impl Context { kid_recv, assembled_packet, |Packet(kid, nonce, payload), hk| { - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, *kid, @@ -362,7 +358,7 @@ impl Context { } } else { // Process recv fragmentation layer. - let result = ctx.hello_defrag.borrow_mut().received_fragment::( + let result = ctx.hello_defrag.borrow_mut().received_fragment::( raw_fragment, app.time(), |n, frag_no, frag_count| { @@ -381,7 +377,7 @@ impl Context { log!(app, ReceivedRawX1); // Process recv challenge layer. let challenge_start = assembled_packet.len() - CHALLENGE_SIZE; - let result = ctx.challenge.borrow_mut().process_hello::( + let result = ctx.challenge.borrow_mut().process_hello::( remote_address, (&assembled_packet[challenge_start..]).try_into().unwrap(), ); @@ -391,7 +387,7 @@ impl Context { challenge_packet.extend(&assembled_packet[..KID_SIZE]); challenge_packet.extend(&challenge); let nonce = to_nonce(PACKET_TYPE_CHALLENGE, ctx.rng.borrow_mut().next_u64()); - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, 0, @@ -413,7 +409,7 @@ impl Context { to_aes_nonce(&n), assembled_packet, |Packet(kid, nonce, payload), hk| { - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, *kid, @@ -436,7 +432,7 @@ impl Context { { if let Some(Some(session)) = ctx.session_map.borrow_mut().get(&kid_recv).map(|r| r.upgrade()) { let mut zeta = session.0.borrow_mut(); - respond_to_challenge::( + respond_to_challenge::( &mut zeta, &ctx.rng, &assembled_packet[KID_SIZE..].try_into().unwrap(), @@ -466,7 +462,7 @@ impl Context { /// * `payload` - Data to send pub fn send( &mut self, - session: &Arc>, + session: &Arc>, send: impl FnMut(Vec) -> bool, mut mtu: usize, payload: Vec, @@ -474,8 +470,8 @@ impl Context { debug_assert_eq!(session.0.borrow().ctx.as_ptr(), Arc::as_ptr(&self.0)); mtu = mtu.max(MIN_TRANSPORT_MTU); let mut zeta = session.0.borrow_mut(); - send_payload::(&mut zeta, payload, |Packet(kid, nonce, payload), hk| { - let result = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(nonce), &payload, hk); + send_payload::(&mut zeta, payload, |Packet(kid, nonce, payload), hk| { + let result = send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(nonce), &payload, hk); if matches!(result, Err(true)) { return Err(SendError::DataTooLarge); } @@ -490,14 +486,11 @@ impl Context { /// a problem. It is completely fine to call this function more often than the returned interval. /// /// * `send_to` - Function to get a sender and an MTU to send something over an active session - pub fn service) -> bool>( + pub fn service, SendFn: FnMut(Vec) -> bool>( &mut self, mut app: App, - mut send_to: impl FnMut(&Arc>) -> Option<(SendFn, usize)>, - ) -> i64 - where - App: ApplicationLayer, - { + mut send_to: impl FnMut(&Arc>) -> Option<(SendFn, usize)>, + ) -> i64 { let ctx = &self.0; let sessions = ctx.sessions.borrow_mut(); let current_time = app.time(); @@ -514,7 +507,7 @@ impl Context { |Packet(kid, nonce, payload): &Packet, hk| { if let Some((send_fragment, mut mtu)) = send_to(&session) { mtu = mtu.max(MIN_TRANSPORT_MTU); - let _ = send_with_fragmentation::( + let _ = send_with_fragmentation::( send_fragment, mtu, *kid, @@ -530,6 +523,6 @@ impl Context { } } ctx.hello_defrag.borrow_mut().service(current_time); - (Crypto::SETTINGS.resend_time as i64).min(next_timer - current_time) + (C::SETTINGS.resend_time as i64).min(next_timer - current_time) } } diff --git a/reference/src/fragmentation.rs b/reference/src/fragmentation.rs index da1a862..11a022f 100644 --- a/reference/src/fragmentation.rs +++ b/reference/src/fragmentation.rs @@ -86,7 +86,7 @@ impl DefragBuffer { } /// Corresponds to the authentication and defragmentation algorithm described in Section 6.1. - pub fn received_fragment( + pub fn received_fragment>( &self, mut raw_fragment: Vec, current_time: i64, @@ -98,7 +98,7 @@ impl DefragBuffer { } if let Some(hk_recv) = self.hk_recv.as_ref() { - ::Prp::decrypt_in_place( + C::Prp::decrypt_in_place( hk_recv, (&mut raw_fragment[HEADER_AUTH_START..HEADER_AUTH_END]) .try_into() @@ -118,7 +118,7 @@ impl DefragBuffer { return Err(e); } - let expiration_time = current_time + App::Crypto::SETTINGS.fragment_assembly_timeout as i64; + let expiration_time = current_time + C::SETTINGS.fragment_assembly_timeout as i64; let mut map = self.fragment_map.borrow_mut(); match map.entry(n) { Entry::Occupied(mut entry) => { diff --git a/reference/src/zeta.rs b/reference/src/zeta.rs index ccfde48..c9de2b2 100644 --- a/reference/src/zeta.rs +++ b/reference/src/zeta.rs @@ -19,14 +19,14 @@ use crate::symmetric_state::SymmetricState; use crate::LogEvent::*; /// Corresponds to the Zeta State Machine found in Section 4.1. -pub(crate) struct Zeta { - pub ctx: Weak>, +pub(crate) struct Zeta { + pub ctx: Weak>, /// An arbitrary application defined object associated with each session. - pub session_data: Crypto::SessionData, + pub session_data: C::SessionData, /// Is true if the local peer acted as Bob, the responder in the initial key exchange. pub was_bob: bool, - s_remote: Crypto::PublicKey, + s_remote: C::PublicKey, send_counter: u64, key_creation_counter: u64, @@ -38,7 +38,7 @@ pub(crate) struct Zeta { resend_timer: i64, timeout_timer: i64, - pub beta: ZetaAutomata, + pub beta: ZetaAutomata, pub counter_antireplay_window: [u64; COUNTER_WINDOW_MAX_OOO], pub defrag: DefragBuffer, @@ -46,16 +46,16 @@ pub(crate) struct Zeta { /// ZeroTier Secure Session Protocol (ZSSP) Session. /// /// A FIPS/NIST compliant variant of Noise_XK with hybrid Kyber1024 PQ data forward secrecy. -pub struct Session(pub(crate) RefCell>); +pub struct Session(pub(crate) RefCell>); /// Corresponds to State B_2 of the Zeta State Machine found in Section 4.1 - Definition 3. -pub(crate) struct StateB2 { +pub(crate) struct StateB2 { ratchet_state: RatchetState, kid_send: NonZeroU32, pub kid_recv: NonZeroU32, pub hk_send: Zeroizing<[u8; AES_256_KEY_SIZE]>, - e_secret: Crypto::KeyPair, - noise: SymmetricState, + e_secret: C::KeyPair, + noise: SymmetricState, pub defrag: DefragBuffer, } @@ -78,18 +78,18 @@ pub(crate) struct Packet(pub u32, pub [u8; AES_GCM_NONCE_SIZE], pub Vec); /// Corresponds to State A_1 of the Zeta State Machine found in Section 4.1. #[derive(Clone)] -pub(crate) struct StateA1 { - noise: SymmetricState, - e_secret: Crypto::KeyPair, - e1_secret: Crypto::Kem, +pub(crate) struct StateA1 { + noise: SymmetricState, + e_secret: C::KeyPair, + e1_secret: C::Kem, identity: Vec, packet: Packet, } /// Corresponds to the ZKE Automata found in Section 4.1 - Definition 2. -pub(crate) enum ZetaAutomata { +pub(crate) enum ZetaAutomata { Null, - A1(StateA1), + A1(StateA1), A3 { identity: Vec, packet: Packet, @@ -97,8 +97,8 @@ pub(crate) enum ZetaAutomata { S1, S2, R1 { - noise: SymmetricState, - e_secret: Crypto::KeyPair, + noise: SymmetricState, + e_secret: C::KeyPair, k1: Vec, }, R2 { @@ -106,24 +106,24 @@ pub(crate) enum ZetaAutomata { }, } -impl SymmetricState { - fn write_e(&mut self, rng: &RefCell, packet: &mut Vec) -> Crypto::KeyPair { - let e_secret = Crypto::KeyPair::generate(rng.borrow_mut().deref_mut()); +impl SymmetricState { + fn write_e(&mut self, rng: &RefCell, packet: &mut Vec) -> C::KeyPair { + let e_secret = C::KeyPair::generate(rng.borrow_mut().deref_mut()); let pub_key = e_secret.public_key_bytes(); packet.extend(&pub_key); self.mix_hash(&pub_key); self.mix_key(&pub_key); e_secret } - fn read_e(&mut self, i: &mut usize, packet: &Vec) -> Option { + fn read_e(&mut self, i: &mut usize, packet: &Vec) -> Option { let j = *i + P384_PUBLIC_KEY_SIZE; let pub_key = &packet[*i..j]; self.mix_hash(pub_key); self.mix_key(pub_key); *i = j; - Crypto::PublicKey::from_bytes((pub_key).try_into().unwrap()) + C::PublicKey::from_bytes((pub_key).try_into().unwrap()) } - fn mix_dh(&mut self, secret: &Crypto::KeyPair, remote: &Crypto::PublicKey) { + fn mix_dh(&mut self, secret: &C::KeyPair, remote: &C::PublicKey) { let ecdh = Zeroizing::new(secret.agree(&remote)); self.mix_key(ecdh.as_ref()); } @@ -161,11 +161,11 @@ fn gen_kid(session_map: &HashMap, rng: &mut impl RngCore) -> N } } } -fn remap( - session: &Arc>, - zeta: &Zeta, - rng: &RefCell, - session_map: &SessionMap, +fn remap( + session: &Arc>, + zeta: &Zeta, + rng: &RefCell, + session_map: &SessionMap, ) -> NonZeroU32 { let mut session_map = session_map.borrow_mut(); let weak = if let Some(Some(weak)) = zeta.key_ref(true).recv.kid.as_ref().map(|kid| session_map.remove(kid)) { @@ -178,7 +178,7 @@ fn remap( new_kid_recv } -impl Zeta { +impl Zeta { pub(crate) fn check_counter_window(&self, c: u64) -> bool { let slot = &self.counter_antireplay_window[c as usize % self.counter_antireplay_window.len()]; let adj_counter = c.saturating_add(1); @@ -231,23 +231,23 @@ impl Zeta { c, c >= self .key_creation_counter - .saturating_add(Crypto::SETTINGS.rekey_after_key_uses), + .saturating_add(C::SETTINGS.rekey_after_key_uses), )) } } -fn create_a1_state( - rng: &RefCell<::Rng>, - s_remote: &::PublicKey, +fn create_a1_state>( + rng: &RefCell, + s_remote: &C::PublicKey, kid_recv: NonZeroU32, ratchet_state1: &RatchetState, ratchet_state2: Option<&RatchetState>, identity: Vec, -) -> StateA1 { +) -> StateA1 { // <- s // ... // -> e, es, e1 - let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); let mut x1 = Vec::new(); // Noise process prologue. let kid = kid_recv.get().to_be_bytes(); @@ -260,7 +260,7 @@ fn create_a1_state( noise.mix_dh(&e_secret, s_remote); // Process message pattern 1 e1 token. let i = x1.len(); - let (e1_secret, e1_public) = ::Kem::generate(rng.borrow_mut().deref_mut()); + let (e1_secret, e1_public) = C::Kem::generate(rng.borrow_mut().deref_mut()); x1.extend(&e1_public); noise.encrypt_and_hash_in_place(to_nonce(PACKET_TYPE_HANDSHAKE_HELLO, 0), i, &mut x1); // Process message pattern 1 payload. @@ -285,14 +285,14 @@ fn create_a1_state( } } /// Corresponds to Transition Algorithm 1 found in Section 4.3. -pub(crate) fn trans_to_a1( +pub(crate) fn trans_to_a1>( mut app: App, - ctx: &Arc>, - s_remote: ::PublicKey, - session_data: ::SessionData, + ctx: &Arc>, + s_remote: C::PublicKey, + session_data: C::SessionData, identity: Vec, send: impl FnOnce(&Packet), -) -> Result>, OpenError> { +) -> Result>, OpenError> { let ratchet_states = app .restore_by_identity(&s_remote, &session_data) .map_err(|e| OpenError::StorageError(e))?; @@ -301,7 +301,7 @@ pub(crate) fn trans_to_a1( let mut session_map = ctx.session_map.borrow_mut(); let kid_recv = gen_kid(session_map.deref(), ctx.rng.borrow_mut().deref_mut()); - let a1 = create_a1_state::(&ctx.rng, &s_remote, kid_recv, &state1, state2.as_ref(), identity); + let a1 = create_a1_state::(&ctx.rng, &s_remote, kid_recv, &state1, state2.as_ref(), identity); let packet = a1.packet.clone(); let (hk_recv, hk_send) = a1.noise.get_ask(LABEL_HEADER_KEY); @@ -321,8 +321,8 @@ pub(crate) fn trans_to_a1( ratchet_state1: state1, ratchet_state2: state2, hk_send, - resend_timer: current_time + ::SETTINGS.resend_time as i64, - timeout_timer: current_time + ::SETTINGS.initial_offer_timeout as i64, + resend_timer: current_time + C::SETTINGS.resend_time as i64, + timeout_timer: current_time + C::SETTINGS.initial_offer_timeout as i64, beta: ZetaAutomata::A1(a1), }; zeta.key_mut(true).recv.kid = Some(kid_recv); @@ -338,14 +338,14 @@ pub(crate) fn trans_to_a1( Ok(session) } /// Corresponds to Algorithm 13 found in Section 5. -pub(crate) fn respond_to_challenge( - zeta: &mut Zeta, - rng: &RefCell<::Rng>, +pub(crate) fn respond_to_challenge>( + zeta: &mut Zeta, + rng: &RefCell, challenge: &[u8; CHALLENGE_SIZE], ) { if let ZetaAutomata::A1(StateA1 { packet: Packet(_, _, x1), .. }) = &mut zeta.beta { let response_start = x1.len() - CHALLENGE_SIZE; - respond_to_challenge_in_place::<::Rng, ::Hash>( + respond_to_challenge_in_place::( rng.borrow_mut().deref_mut(), challenge, (&mut x1[response_start..]).try_into().unwrap(), @@ -353,9 +353,9 @@ pub(crate) fn respond_to_challenge( } } /// Corresponds to Transition Algorithm 2 found in Section 4.3. -pub(crate) fn received_x1_trans( +pub(crate) fn received_x1_trans>( app: &mut App, - ctx: &ContextInner, + ctx: &ContextInner, n: [u8; AES_GCM_NONCE_SIZE], mut x1: Vec, send: impl FnOnce(&Packet, &[u8; AES_256_KEY_SIZE]), @@ -371,7 +371,7 @@ pub(crate) fn received_x1_trans( if &n[AES_GCM_NONCE_SIZE - 8..] != &x1[x1.len() - 8..] { return Err(byzantine_fault!(FailedAuth, true)); } - let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_XK); let mut i = 0; // Noise process prologue. let j = i + KID_SIZE; @@ -432,7 +432,7 @@ pub(crate) fn received_x1_trans( noise.mix_dh(&e_secret, &e_remote); // Process message pattern 2 ekem1 token. let i = x2.len(); - let (ekem1, ekem1_secret) = ::Kem::encapsulate( + let (ekem1, ekem1_secret) = C::Kem::encapsulate( ctx.rng.borrow_mut().deref_mut(), (&x1[e1_start..e1_end]).try_into().unwrap(), ) @@ -479,11 +479,11 @@ pub(crate) fn received_x1_trans( Ok(()) } /// Corresponds to Transition Algorithm 3 found in Section 4.3. -pub(crate) fn received_x2_trans( - zeta: &mut Zeta, - session: &Arc>, +pub(crate) fn received_x2_trans>( + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - ctx: &Arc>, + ctx: &Arc>, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], mut x2: Vec, @@ -536,7 +536,7 @@ pub(crate) fn received_x2_trans( let payload: [u8; KID_SIZE] = x2[i..j].try_into().unwrap(); let tag = x2[j..k].try_into().unwrap(); // Check for which ratchet key Bob wants to use. - let test_ratchet_key = |ratchet_key| -> Option<(NonZeroU32, SymmetricState)> { + let test_ratchet_key = |ratchet_key| -> Option<(NonZeroU32, SymmetricState)> { let mut noise = noise.clone(); let mut payload = payload.clone(); // Process message pattern 2 psk token. @@ -619,8 +619,8 @@ pub(crate) fn received_x2_trans( zeta.ratchet_state1 = new_ratchet_state; let current_time = app.time(); zeta.key_creation_counter = zeta.send_counter; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; - zeta.timeout_timer = current_time + ::SETTINGS.initial_offer_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.initial_offer_timeout as i64; let packet = Packet(kid_send.get(), n, x3); zeta.beta = ZetaAutomata::A3 { identity, packet: packet.clone() }; @@ -639,8 +639,8 @@ pub(crate) fn received_x2_trans( } result.map(|_| should_warn_missing_ratchet) } -fn send_control( - zeta: &mut Zeta, +fn send_control>( + zeta: &mut Zeta, packet_type: u8, mut payload: Vec, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), @@ -648,7 +648,7 @@ fn send_control( if let Some((c, _)) = zeta.get_counter() { if let (Some(kek), Some(kid)) = (zeta.key_ref(false).send.kek.as_ref(), zeta.key_ref(false).send.kid) { let nonce = to_nonce(packet_type, c); - let tag = ::Aead::encrypt_in_place(kek, &nonce, None, &mut payload); + let tag = C::Aead::encrypt_in_place(kek, &nonce, None, &mut payload); payload.extend(tag); send(&Packet(kid.get(), nonce, payload), Some(&zeta.hk_send)); @@ -661,14 +661,14 @@ fn send_control( } } /// Corresponds to Transition Algorithm 4 found in Section 4.3. -pub(crate) fn received_x3_trans( - zeta: StateB2, +pub(crate) fn received_x3_trans>( + zeta: StateB2, app: &mut App, - ctx: &Arc>, + ctx: &Arc>, kid: NonZeroU32, mut x3: Vec, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), -) -> Result<(Arc>, bool), ReceiveError> { +) -> Result<(Arc>, bool), ReceiveError> { use FaultType::*; // -> s, se if !(HANDSHAKE_COMPLETION_MIN_SIZE..=HANDSHAKE_COMPLETION_MAX_SIZE).contains(&x3.len()) { @@ -687,8 +687,8 @@ pub(crate) fn received_x3_trans( if !noise.decrypt_and_hash_in_place(to_nonce(PACKET_TYPE_HANDSHAKE_COMPLETION, 1), &mut x3[i..j], tag) { return Err(byzantine_fault!(FailedAuth, true)); } - let s_remote = ::PublicKey::from_bytes((&x3[i..j]).try_into().unwrap()) - .ok_or(byzantine_fault!(FailedAuth, true))?; + let s_remote = + C::PublicKey::from_bytes((&x3[i..j]).try_into().unwrap()).ok_or(byzantine_fault!(FailedAuth, true))?; i = k; // Process message pattern 3 se token. noise.mix_dh(&zeta.e_secret, &s_remote); @@ -712,7 +712,7 @@ pub(crate) fn received_x3_trans( let create_reject = || { let mut d = Vec::::new(); let n = to_nonce(PACKET_TYPE_SESSION_REJECTED, c); - let tag = ::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); + let tag = C::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); d.extend(&tag); // We just used a counter with this key, but we are not storing // the fact we used it in memory. This is currently ok because the @@ -757,7 +757,7 @@ pub(crate) fn received_x3_trans( let mut c1 = Vec::new(); let n = to_nonce(PACKET_TYPE_KEY_CONFIRM, c); - let tag = ::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); + let tag = C::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); c1.extend(&tag); let (nk1, nk2) = noise.split(); @@ -787,8 +787,8 @@ pub(crate) fn received_x3_trans( ratchet_state1: new_ratchet_state, ratchet_state2: None, hk_send: zeta.hk_send.clone(), - resend_timer: current_time + ::SETTINGS.resend_time as i64, - timeout_timer: current_time + ::SETTINGS.rekey_timeout as i64, + resend_timer: current_time + C::SETTINGS.resend_time as i64, + timeout_timer: current_time + C::SETTINGS.rekey_timeout as i64, beta: ZetaAutomata::S1, counter_antireplay_window: std::array::from_fn(|_| 0), defrag: zeta.defrag, @@ -811,10 +811,10 @@ pub(crate) fn received_x3_trans( } } /// Corresponds to Transition Algorithm 5 found in Section 4.3. -pub(crate) fn received_c1_trans( - zeta: &mut Zeta, +pub(crate) fn received_c1_trans>( + zeta: &mut Zeta, app: &mut App, - rng: &RefCell<::Rng>, + rng: &RefCell, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], c1: Vec, @@ -842,7 +842,7 @@ pub(crate) fn received_c1_trans( .as_ref() .ok_or(byzantine_fault!(OutOfSequence, true))?; let tag = c1[..].try_into().unwrap(); - if !::Aead::decrypt_in_place(specified_key, &n, None, &mut [], tag) { + if !C::Aead::decrypt_in_place(specified_key, &n, None, &mut [], tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -872,17 +872,14 @@ pub(crate) fn received_c1_trans( zeta.ratchet_state2 = None; zeta.key_index ^= true; - let r = rng.borrow_mut().next_u64() % ::SETTINGS.rekey_time_max_jitter; - zeta.timeout_timer = app.time() - + ::SETTINGS - .rekey_after_time - .saturating_sub(r) as i64; + let r = rng.borrow_mut().next_u64() % C::SETTINGS.rekey_time_max_jitter; + zeta.timeout_timer = app.time() + C::SETTINGS.rekey_after_time.saturating_sub(r) as i64; zeta.resend_timer = i64::MAX; zeta.beta = ZetaAutomata::S2; } } let c2 = Vec::new(); - if !send_control::(zeta, PACKET_TYPE_ACK, c2, send) { + if !send_control::(zeta, PACKET_TYPE_ACK, c2, send) { return Err(byzantine_fault!(OutOfSequence, true)); } @@ -890,10 +887,10 @@ pub(crate) fn received_c1_trans( } /// Corresponds to the trivial Transition Algorithm described for processing C_2 packets found in /// Section 4.3. -pub(crate) fn received_c2_trans( - zeta: &mut Zeta, +pub(crate) fn received_c2_trans>( + zeta: &mut Zeta, app: &mut App, - rng: &RefCell<::Rng>, + rng: &RefCell, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], c2: Vec, @@ -913,13 +910,7 @@ pub(crate) fn received_c2_trans( } let tag = c2[..].try_into().unwrap(); - if !::Aead::decrypt_in_place( - zeta.key_ref(false).recv.kek.as_ref().unwrap(), - &n, - None, - &mut [], - tag, - ) { + if !C::Aead::decrypt_in_place(zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, &mut [], tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -927,19 +918,16 @@ pub(crate) fn received_c2_trans( return Err(byzantine_fault!(ExpiredCounter, true)); } - let r = rng.borrow_mut().next_u64() % ::SETTINGS.rekey_time_max_jitter; - zeta.timeout_timer = app.time() - + ::SETTINGS - .rekey_after_time - .saturating_sub(r) as i64; + let r = rng.borrow_mut().next_u64() % C::SETTINGS.rekey_time_max_jitter; + zeta.timeout_timer = app.time() + C::SETTINGS.rekey_after_time.saturating_sub(r) as i64; zeta.resend_timer = i64::MAX; zeta.beta = ZetaAutomata::S2; Ok(()) } /// Corresponds to the trivial Transition Algorithm described for processing D packets found in /// Section 4.3. -pub(crate) fn received_d_trans( - zeta: &mut Zeta, +pub(crate) fn received_d_trans>( + zeta: &mut Zeta, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], d: Vec, @@ -954,13 +942,7 @@ pub(crate) fn received_d_trans( } let tag = d[..].try_into().unwrap(); - if !::Aead::decrypt_in_place( - zeta.key_ref(true).recv.kek.as_ref().unwrap(), - &n, - None, - &mut [], - tag, - ) { + if !C::Aead::decrypt_in_place(zeta.key_ref(true).recv.kek.as_ref().unwrap(), &n, None, &mut [], tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -972,10 +954,10 @@ pub(crate) fn received_d_trans( Ok(()) } /// Corresponds to the timer rules of the Zeta State Machine found in Section 4.1 - Definition 3. -pub(crate) fn service( - zeta: &mut Zeta, - session: &Arc>, - ctx: &Arc>, +pub(crate) fn service>( + zeta: &mut Zeta, + session: &Arc>, + ctx: &Arc>, app: &mut App, current_time: i64, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), @@ -984,7 +966,7 @@ pub(crate) fn service( timeout_trans(zeta, session, app, ctx, current_time, send); } else if zeta.resend_timer <= current_time { // Corresponds to the resend timer rules found in Section 4.1 - Definition 3. - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; let (p, control_payload) = match &zeta.beta { ZetaAutomata::Null => return, @@ -1011,15 +993,15 @@ pub(crate) fn service( } }; - send_control::(zeta, p, control_payload, send); + send_control::(zeta, p, control_payload, send); } } /// Corresponds to the timeout timer Transition Algorithm described in Section 4.1 - Definition 3. -fn timeout_trans( - zeta: &mut Zeta, - session: &Arc>, +fn timeout_trans>( + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - ctx: &Arc>, + ctx: &Arc>, current_time: i64, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), ) { @@ -1033,7 +1015,7 @@ fn timeout_trans( } let new_kid_recv = remap(session, &zeta, &ctx.rng, &ctx.session_map); - let a1 = create_a1_state::( + let a1 = create_a1_state::( &ctx.rng, &zeta.s_remote, new_kid_recv, @@ -1047,8 +1029,8 @@ fn timeout_trans( zeta.hk_send = hk_send; *zeta.key_mut(true) = DuplexKey::default(); zeta.key_mut(true).recv.kid = Some(new_kid_recv); - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; - zeta.timeout_timer = current_time + ::SETTINGS.initial_offer_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.initial_offer_timeout as i64; zeta.beta = ZetaAutomata::A1(a1); zeta.defrag = DefragBuffer::new(Some(hk_recv)); @@ -1081,11 +1063,11 @@ fn timeout_trans( noise.encrypt_and_hash_in_place(to_nonce(PACKET_TYPE_REKEY_INIT, 0), i, &mut k1); zeta.key_mut(true).recv.kid = Some(new_kid_recv); - zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; zeta.beta = ZetaAutomata::R1 { noise, e_secret, k1: k1.clone() }; - send_control::(zeta, PACKET_TYPE_REKEY_INIT, k1, send); + send_control::(zeta, PACKET_TYPE_REKEY_INIT, k1, send); } ZetaAutomata::S1 { .. } => { log!(app, TimeoutKeyConfirm(session)); @@ -1102,13 +1084,13 @@ fn timeout_trans( } } /// Corresponds to Transition Algorithm 7 found in Section 4.3. -pub(crate) fn received_k1_trans( - zeta: &mut Zeta, - session: &Arc>, +pub(crate) fn received_k1_trans>( + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - rng: &RefCell<::Rng>, - session_map: &SessionMap, - s_secret: &::KeyPair, + rng: &RefCell, + session_map: &SessionMap, + s_secret: &C::KeyPair, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], mut k1: Vec, @@ -1139,7 +1121,7 @@ pub(crate) fn received_k1_trans( let i = k1.len() - AES_GCM_TAG_SIZE; let tag = k1[i..].try_into().unwrap(); - if !::Aead::decrypt_in_place( + if !C::Aead::decrypt_in_place( zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, @@ -1156,7 +1138,7 @@ pub(crate) fn received_k1_trans( let result = (|| { let mut i = 0; - let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_KK); + let mut noise = SymmetricState::::initialize(PROTOCOL_NAME_NOISE_KK); // Noise process prologue. noise.mix_hash(&zeta.s_remote.to_bytes()); noise.mix_hash(&s_secret.public_key_bytes()); @@ -1220,11 +1202,11 @@ pub(crate) fn received_k1_trans( zeta.ratchet_state1 = new_ratchet_state; let current_time = app.time(); zeta.key_creation_counter = zeta.send_counter; - zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; zeta.beta = ZetaAutomata::R2 { k2: k2.clone() }; - send_control::(zeta, PACKET_TYPE_REKEY_COMPLETE, k2, send); + send_control::(zeta, PACKET_TYPE_REKEY_COMPLETE, k2, send); Ok(()) })(); if matches!(result, Err(ReceiveError::ByzantineFault { .. })) { @@ -1233,8 +1215,8 @@ pub(crate) fn received_k1_trans( result } /// Corresponds to Transition Algorithm 8 found in Section 4.3. -pub(crate) fn received_k2_trans( - zeta: &mut Zeta, +pub(crate) fn received_k2_trans>( + zeta: &mut Zeta, app: &mut App, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], @@ -1257,7 +1239,7 @@ pub(crate) fn received_k2_trans( let i = k2.len() - AES_GCM_TAG_SIZE; let tag = k2[i..].try_into().unwrap(); - if !::Aead::decrypt_in_place( + if !C::Aead::decrypt_in_place( zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, @@ -1319,12 +1301,12 @@ pub(crate) fn received_k2_trans( zeta.key_index ^= true; let current_time = app.time(); zeta.key_creation_counter = zeta.send_counter; - zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + C::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + C::SETTINGS.resend_time as i64; zeta.beta = ZetaAutomata::S1; let c1 = Vec::new(); - send_control::(zeta, PACKET_TYPE_KEY_CONFIRM, c1, send); + send_control::(zeta, PACKET_TYPE_KEY_CONFIRM, c1, send); Ok(()) } else { unreachable!() @@ -1336,8 +1318,8 @@ pub(crate) fn received_k2_trans( result } /// Corresponds to Algorithm 9 found in Section 4.3. -pub(crate) fn send_payload( - zeta: &mut Zeta, +pub(crate) fn send_payload( + zeta: &mut Zeta, mut payload: Vec, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>) -> Result<(), SendError>, ) -> Result<(), SendError> { @@ -1359,7 +1341,7 @@ pub(crate) fn send_payload( } let n = to_nonce(PACKET_TYPE_DATA, c); - let tag = Crypto::Aead::encrypt_in_place(zeta.key_ref(false).send.nk.as_ref().unwrap(), &n, None, &mut payload); + let tag = C::Aead::encrypt_in_place(zeta.key_ref(false).send.nk.as_ref().unwrap(), &n, None, &mut payload); payload.extend(&tag); send( @@ -1372,8 +1354,8 @@ pub(crate) fn send_payload( } } /// Corresponds to Algorithm 10 found in Section 4.3. -pub(crate) fn received_payload_in_place( - zeta: &mut Zeta, +pub(crate) fn received_payload_in_place>( + zeta: &mut Zeta, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], payload: &mut Vec, @@ -1397,7 +1379,7 @@ pub(crate) fn received_payload_in_place( let specified_key = zeta.key_ref(is_other).recv.nk.as_ref(); let specified_key = specified_key.ok_or(byzantine_fault!(OutOfSequence, true))?; let tag = payload[i..].try_into().unwrap(); - if !::Aead::decrypt_in_place(specified_key, &n, None, &mut payload[..i], &tag) { + if !C::Aead::decrypt_in_place(specified_key, &n, None, &mut payload[..i], &tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -1411,7 +1393,7 @@ pub(crate) fn received_payload_in_place( Ok(()) } -impl Session { +impl Session { /// Mark a session as expired. This will make it impossible for this session to successfully /// receive or send data or control packets. It is recommended to simply `drop` the session /// instead, but this can provide some reassurance in complex shared ownership situations. @@ -1420,7 +1402,7 @@ impl Session { } } -impl Drop for Session { +impl Drop for Session { fn drop(&mut self) { self.expire(); }