diff --git a/examples/basic_test.rs b/examples/basic_test.rs index 7513eef..87335a1 100644 --- a/examples/basic_test.rs +++ b/examples/basic_test.rs @@ -7,10 +7,11 @@ */ use std::collections::HashMap; +use std::convert::Infallible; use std::iter::ExactSizeIterator; use std::str::FromStr; use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{mpsc, Arc, Mutex}; +use std::sync::{mpsc, Arc}; use std::thread; use std::time::{Duration, Instant}; @@ -18,7 +19,7 @@ use rand_core::OsRng; use rand_core::RngCore; use zssp_proto::application::{ - AcceptAction, ApplicationLayer, RatchetState, RatchetStates, RatchetUpdate, Settings, RATCHET_SIZE, + AcceptAction, ApplicationLayer, RatchetState, RatchetStates, RatchetUpdate, Settings, RATCHET_SIZE, CryptoLayer, }; use zssp_proto::crypto::P384KeyPair; use zssp_proto::crypto_impl::{ @@ -31,7 +32,7 @@ const TEST_MTU: usize = 1500; struct TestApplication { time: Instant, name: &'static str, - ratchets: Mutex, + ratchets: Ratchets, } struct Ratchets { @@ -44,8 +45,7 @@ impl Ratchets { } } -#[allow(unused)] -impl ApplicationLayer for &TestApplication { +impl CryptoLayer for TestApplication { const SETTINGS: Settings = Settings { initial_offer_timeout: Settings::INITIAL_OFFER_TIMEOUT_MS, rekey_timeout: 60 * 1000, @@ -63,18 +63,21 @@ impl ApplicationLayer for &TestApplication { type KeyPair = P384CrateKeyPair; type Kem = RustKyber1024PrivateKey; - type StorageError = std::convert::Infallible; type SessionData = u128; - - fn hello_requires_recognized_ratchet(&self) -> bool { +} +#[allow(unused)] +impl ApplicationLayer for &mut TestApplication { + type Crypto = TestApplication; + type StorageError = Infallible; + fn hello_requires_recognized_ratchet(&mut self) -> bool { false } - fn initiator_disallows_downgrade(&self, session: &Arc>) -> bool { + fn initiator_disallows_downgrade(&mut self, session: &Arc>) -> bool { true } - fn check_accept_session(&self, remote_static_key: &Self::PublicKey, identity: &[u8]) -> AcceptAction { + fn check_accept_session(&mut self, remote_static_key: &P384CratePublicKey, identity: &[u8]) -> AcceptAction { AcceptAction { session_data: Some(1), responder_disallows_downgrade: true, @@ -83,49 +86,46 @@ impl ApplicationLayer for &TestApplication { } fn restore_by_fingerprint( - &self, + &mut self, ratchet_fingerprint: &[u8; RATCHET_SIZE], - ) -> Result, Self::StorageError> { - let ratchets = self.ratchets.lock().unwrap(); - Ok(ratchets.rf_map.get(ratchet_fingerprint).cloned()) + ) -> Result, Infallible> { + Ok(self.ratchets.rf_map.get(ratchet_fingerprint).cloned()) } fn restore_by_identity( - &self, - remote_static_key: &Self::PublicKey, - session_data: &Self::SessionData, - ) -> Result, Self::StorageError> { - let ratchets = self.ratchets.lock().unwrap(); - Ok(ratchets.peer_map.get(session_data).cloned()) + &mut self, + remote_static_key: &P384CratePublicKey, + session_data: &u128, + ) -> Result, Infallible> { + Ok(self.ratchets.peer_map.get(session_data).cloned()) } fn save_ratchet_state( - &self, - remote_static_key: &Self::PublicKey, - session_data: &Self::SessionData, + &mut self, + remote_static_key: &P384CratePublicKey, + session_data: &u128, update_data: RatchetUpdate<'_>, - ) -> Result<(), Self::StorageError> { - let mut ratchets = self.ratchets.lock().unwrap(); - ratchets.peer_map.insert(*session_data, update_data.to_states()); + ) -> Result<(), Infallible> { + self.ratchets.peer_map.insert(*session_data, update_data.to_states()); if let Some(rf) = update_data.added_fingerprint() { - ratchets.rf_map.insert(*rf, update_data.state1.clone()); + self.ratchets.rf_map.insert(*rf, update_data.state1.clone()); println!("[{}] new ratchet #{}", self.name, update_data.state1.chain_len()); } if let Some(rf) = update_data.deleted_fingerprint1() { - ratchets.rf_map.remove(rf); + self.ratchets.rf_map.remove(rf); } if let Some(rf) = update_data.deleted_fingerprint2() { - ratchets.rf_map.remove(rf); + self.ratchets.rf_map.remove(rf); } Ok(()) } - fn time(&self) -> i64 { + fn time(&mut self) -> i64 { self.time.elapsed().as_millis() as i64 } - fn event_log(&self, event: zssp_proto::LogEvent) { + fn event_log(&mut self, event: zssp_proto::LogEvent) { println!(">[{}] {:?}", self.name, event); } } @@ -133,7 +133,7 @@ impl ApplicationLayer for &TestApplication { fn alice_main( run: &AtomicBool, packet_success_rate: u32, - alice_app: &TestApplication, + mut alice_app: TestApplication, alice_out: mpsc::SyncSender>, alice_in: mpsc::Receiver>, recursive_out: mpsc::SyncSender>, @@ -141,7 +141,7 @@ fn alice_main( bob_pubkey: P384CratePublicKey, ) { let startup_time = std::time::Instant::now(); - let mut context = zssp_proto::Context::<&TestApplication>::new(alice_keypair, OsRng); + let mut context = zssp_proto::Context::::new(alice_keypair, OsRng); let mut next_service = startup_time.elapsed().as_millis() as i64 + 500; let test_data = [1u8; TEST_MTU * 10]; let mut up = false; @@ -153,7 +153,7 @@ fn alice_main( alice_session = Some( context .open( - alice_app, + &mut alice_app, |b| alice_out.send(b).is_ok(), TEST_MTU, bob_pubkey.clone(), @@ -173,7 +173,7 @@ fn alice_main( use zssp_proto::result::ReceiveOk::*; use zssp_proto::result::SessionEvent::*; match context.receive( - alice_app, + &mut alice_app, |b| alice_out.send(b).is_ok(), TEST_MTU, |_| Some((|b| alice_out.send(b).is_ok(), TEST_MTU)), @@ -228,7 +228,7 @@ fn alice_main( if current_time >= next_service { next_service = - current_time + context.service(alice_app, |_| Some((|b| alice_out.send(b).is_ok(), TEST_MTU))); + current_time + context.service(&mut alice_app, |_| Some((|b| alice_out.send(b).is_ok(), TEST_MTU))); } } } @@ -236,14 +236,14 @@ fn alice_main( fn bob_main( run: &AtomicBool, packet_success_rate: u32, - bob_app: &TestApplication, + mut bob_app: TestApplication, bob_out: mpsc::SyncSender>, bob_in: mpsc::Receiver>, recursive_out: mpsc::SyncSender>, bob_keypair: P384CrateKeyPair, ) { let startup_time = std::time::Instant::now(); - let mut context = zssp_proto::Context::<&TestApplication>::new(bob_keypair, OsRng); + let mut context = zssp_proto::Context::::new(bob_keypair, OsRng); let mut last_speed_metric = startup_time.elapsed().as_millis() as i64; let mut next_service = last_speed_metric + 500; let mut transferred = 0u64; @@ -260,7 +260,7 @@ fn bob_main( use zssp_proto::result::ReceiveOk::*; use zssp_proto::result::SessionEvent::*; match context.receive( - bob_app, + &mut bob_app, |b| bob_out.send(b).is_ok(), TEST_MTU, |_| Some((|b| bob_out.send(b).is_ok(), TEST_MTU)), @@ -305,7 +305,7 @@ fn bob_main( } if current_time >= next_service { - next_service = current_time + context.service(bob_app, |_| Some((|b| bob_out.send(b).is_ok(), TEST_MTU))); + next_service = current_time + context.service(&mut bob_app, |_| Some((|b| bob_out.send(b).is_ok(), TEST_MTU))); } } } @@ -317,14 +317,14 @@ fn core(time: u64, packet_success_rate: u32) { let alice_app = TestApplication { time: Instant::now(), name: "alice", - ratchets: Mutex::new(Ratchets::new()), + ratchets: Ratchets::new(), }; let bob_keypair = P384CrateKeyPair::generate(&mut OsRng); let bob_pubkey = bob_keypair.public_key(); let bob_app = TestApplication { time: Instant::now(), name: "bob", - ratchets: Mutex::new(Ratchets::new()), + ratchets: Ratchets::new(), }; let (alice_out, bob_in) = mpsc::sync_channel::>(256); @@ -338,7 +338,7 @@ fn core(time: u64, packet_success_rate: u32) { alice_main( run, packet_success_rate, - &alice_app, + alice_app, alice_out, alice_in, bob_out, @@ -351,7 +351,7 @@ fn core(time: u64, packet_success_rate: u32) { bob_main( run, packet_success_rate, - &bob_app, + bob_app, bob_out, bob_in, alice_out, diff --git a/src/application.rs b/src/application.rs index 03f814c..ba1f018 100644 --- a/src/application.rs +++ b/src/application.rs @@ -83,11 +83,11 @@ impl Default for Settings { } } -/// Trait to implement to integrate the session into an application. +/// Trait to implement to integrate ZSSP into an application. /// -/// Templating the session on this trait lets the code here be almost entirely transport, OS, -/// and use case independent. -pub trait ApplicationLayer: Sized { +/// This is a container trait for all of the cryptographic algorithms ZSSP will use, and all of the +/// generic types that ZSSP will attach to sessions. +pub trait CryptoLayer: Sized { /// These are constants that can be redefined from their defaults to change rekey /// and negotiation timeout behavior. If two sides of a ZSSP session have different constants, /// the protocol will tend to default to the smaller constants. @@ -131,13 +131,20 @@ pub trait ApplicationLayer: Sized { /// for ZSSP to achieve FIPS compliance. type Kem: Kyber1024PrivateKey; + /// An arbitrary opaque object for use by the application that is attached to each session. + type SessionData; +} +/// Trait to implement to integrate ZSSP into an application. +/// +/// 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; /// A user-defined error returned when the `ApplicationLayer` fails to access persistent storage /// for a peer's ratchet states. type StorageError: std::error::Error; - /// An arbitrary opaque object for use by the application that is attached to each session. - type SessionData; - /// 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 @@ -169,14 +176,14 @@ 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. /// To prevent desync, if this function specifies that we should connect, no other open session /// with the same remote peer must exist. Drop or call expire on any pre-existing sessions /// before returning. - fn check_accept_session(&mut self, remote_static_key: &Self::PublicKey, identity: &[u8]) -> AcceptAction; + fn check_accept_session(&mut self, remote_static_key: &::PublicKey, identity: &[u8]) -> 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 @@ -204,8 +211,8 @@ pub trait ApplicationLayer: Sized { /// function `ApplicationLayer::check_accept_session`. fn restore_by_identity( &mut self, - remote_static_key: &Self::PublicKey, - session_data: &Self::SessionData, + remote_static_key: &::PublicKey, + session_data: &::SessionData, ) -> Result, Self::StorageError>; /// Atomically commit the update specified by `update_data` to storage, or return an error if /// the update could not be made. @@ -225,8 +232,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: &Self::PublicKey, - session_data: &Self::SessionData, + remote_static_key: &::PublicKey, + session_data: &::SessionData, update_data: RatchetUpdate<'_>, ) -> Result<(), Self::StorageError>; @@ -234,17 +241,17 @@ pub trait ApplicationLayer: Sized { /// These are provided for debugging, logging or metrics purposes, and must be used for /// nothing else. Do not base protocol-level decisions upon the events passed to this function. #[cfg(feature = "logging")] - fn event_log(&mut self, event: LogEvent<'_, Self>); + fn event_log(&mut self, event: LogEvent<'_, Self::Crypto>); } /// A collection of fields specifying how to complete the key exchange with a specific remote peer, /// used by Bob, the responder, at the very last stage of the key exchange. /// /// Corresponds to the *Accept* callback of Transition Algorithm 4. -pub struct AcceptAction { +pub struct AcceptAction { /// The data object to be attached to the session if we successfully connect. /// If this field is None then we will not connect to this remote peer. - pub session_data: Option, + pub session_data: Option, /// Whether or not we will accept a connection with the remote peer when they do not have a /// ratchet key that we think they should have. pub responder_disallows_downgrade: bool, diff --git a/src/context.rs b/src/context.rs index 837b856..b5855d6 100644 --- a/src/context.rs +++ b/src/context.rs @@ -6,7 +6,7 @@ use std::hash::Hash; use std::num::NonZeroU32; use std::sync::{Arc, Weak}; -use crate::application::ApplicationLayer; +use crate::application::{ApplicationLayer, CryptoLayer}; use crate::challenge::ChallengeContext; use crate::crypto::{AES_256_KEY_SIZE, AES_GCM_NONCE_SIZE}; use crate::fragmentation::{send_with_fragmentation, DefragBuffer}; @@ -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: App::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: Crypto::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: App::KeyPair, mut rng: App::Rng) -> Self { + pub fn new(static_secret_key: Crypto::KeyPair, mut rng: Crypto::Rng) -> Self { let challenge = ChallengeContext::new(&mut rng); Self(Arc::new(ContextInner { rng: RefCell::new(rng), @@ -93,15 +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: App::PublicKey, - session_data: App::SessionData, + static_remote_key: Crypto::PublicKey, + session_data: Crypto::SessionData, identity: Vec, - ) -> Result>, OpenError> { + ) -> Result>, OpenError> where App: ApplicationLayer{ mtu = mtu.max(MIN_TRANSPORT_MTU); if identity.len() > IDENTITY_MAX_SIZE { return Err(OpenError::IdentityTooLarge); @@ -111,13 +111,13 @@ impl Context { // Process zeta layer. trans_to_a1( app, - &ctx, + ctx, static_remote_key, session_data, identity, |Packet(kid, nonce, payload): &Packet| { // Process fragmentation layer. - send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(&nonce), payload, None); + send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(&nonce), payload, None); }, ) } @@ -130,15 +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) -> 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> { + ) -> Result, ReceiveError> where App: ApplicationLayer { use crate::result::FaultType::*; send_unassociated_mtu = send_unassociated_mtu.max(MIN_TRANSPORT_MTU); let ctx = &self.0; @@ -187,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); - send_with_fragmentation::( + send_with_fragmentation::( send_fragment, mtu, *kid, @@ -201,7 +201,7 @@ impl Context { let (p, _) = from_nonce(&pn); let ret = match p { PACKET_TYPE_DATA => { - received_payload_in_place(&mut zeta, kid_recv, to_aes_nonce(&pn), &mut assembled_packet)?; + received_payload_in_place::(&mut zeta, kid_recv, to_aes_nonce(&pn), &mut assembled_packet)?; SessionEvent::Data(assembled_packet) } PACKET_TYPE_HANDSHAKE_RESPONSE => { @@ -286,7 +286,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 } @@ -323,7 +323,7 @@ impl Context { kid_recv, assembled_packet, |Packet(kid, nonce, payload), hk| { - send_with_fragmentation::( + send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, *kid, @@ -369,7 +369,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(), ); @@ -379,7 +379,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()); - send_with_fragmentation::( + send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, 0, @@ -401,7 +401,7 @@ impl Context { to_aes_nonce(&n), assembled_packet, |Packet(kid, nonce, payload), hk| { - send_with_fragmentation::( + send_with_fragmentation::( send_unassociated_reply, send_unassociated_mtu, *kid, @@ -424,7 +424,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(), @@ -454,7 +454,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, @@ -462,8 +462,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| { - send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(nonce), &payload, hk); + send_payload::(&mut zeta, payload, |Packet(kid, nonce, payload), hk| { + send_with_fragmentation::(send, mtu, *kid, to_packet_nonce(nonce), &payload, hk); }) } @@ -474,11 +474,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) -> bool>( &mut self, mut app: App, - mut send_to: impl FnMut(&Arc>) -> Option<(SendFn, usize)>, - ) -> i64 { + mut send_to: impl FnMut(&Arc>) -> Option<(SendFn, usize)>, + ) -> i64 where App: ApplicationLayer { let ctx = &self.0; let sessions = ctx.sessions.borrow_mut(); let current_time = app.time(); @@ -495,7 +495,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); - send_with_fragmentation::( + send_with_fragmentation::( send_fragment, mtu, *kid, @@ -507,10 +507,10 @@ impl Context { }, ); next_timer = next_timer.min(zeta.next_timer()); - zeta.defrag.service::(current_time); + zeta.defrag.service(current_time); } } - ctx.hello_defrag.borrow_mut().service::(current_time); - (App::SETTINGS.resend_time as i64).min(next_timer - current_time) + ctx.hello_defrag.borrow_mut().service(current_time); + (Crypto::SETTINGS.resend_time as i64).min(next_timer - current_time) } } diff --git a/src/crypto_impl/mod.rs b/src/crypto_impl/mod.rs index ccbe469..921af90 100644 --- a/src/crypto_impl/mod.rs +++ b/src/crypto_impl/mod.rs @@ -27,3 +27,38 @@ pub use p384; pub use pqc_kyber; #[cfg(feature = "sha2")] pub use sha2; + +/* +TODO: wrangle the feature flags so we can provide the default set of crypto implementations below. +use crate::application::{Settings, CryptoLayer}; +#[cfg(feature = "default")] +pub trait CrateCryptoLayer { + /// These are constants that can be redefined from their defaults to change rekey + /// and negotiation timeout behavior. If two sides of a ZSSP session have different constants, + /// the protocol will tend to default to the smaller constants. + const SETTINGS: Settings = Settings::new_ms(); + + /// A user-defined error returned when the `ApplicationLayer` fails to access persistent storage + /// for a peer's ratchet states. + type StorageError: std::error::Error; + + /// An arbitrary opaque object for use by the application that is attached to each session. + type SessionData; +} + +use rand_core::OsRng; +#[cfg(feature = "default")] +impl CryptoLayer for Crypto { + type Rng = OsRng; + type Prp = Aes256Crate; + type Aead = AesGcmCrate; + type Hash = Sha512Crate; + type PublicKey = P384CratePublicKey; + type KeyPair = P384CrateKeyPair; + type Kem = RustKyber1024PrivateKey; + + type StorageError = Crypto::StorageError; + + type SessionData = Crypto::SessionData; +} + */ diff --git a/src/fragmentation.rs b/src/fragmentation.rs index 55b425f..c028295 100644 --- a/src/fragmentation.rs +++ b/src/fragmentation.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use zeroize::Zeroizing; -use crate::application::ApplicationLayer; +use crate::application::{CryptoLayer, ApplicationLayer}; use crate::crypto::{Aes256Prp, AES_256_KEY_SIZE}; use crate::proto::*; use crate::result::{byzantine_fault, ReceiveError}; @@ -28,7 +28,7 @@ fn create_fragment_header( } /// Corresponds to the fragmentation algorithm described in Section 6. -pub fn send_with_fragmentation( +pub fn send_with_fragmentation( mut send: impl FnMut(Vec) -> bool, mtu: usize, identifier: u32, @@ -52,7 +52,7 @@ pub fn send_with_fragmentation( fragment.extend(&packet[i..j]); if let Some(hk_send) = hk_send { - App::Prp::encrypt_in_place( + Crypto::Prp::encrypt_in_place( hk_send, (&mut fragment[HEADER_AUTH_START..HEADER_AUTH_END]).try_into().unwrap(), ); @@ -95,7 +95,7 @@ impl DefragBuffer { } if let Some(hk_recv) = self.hk_recv.as_ref() { - App::Prp::decrypt_in_place( + ::Prp::decrypt_in_place( hk_recv, (&mut raw_fragment[HEADER_AUTH_START..HEADER_AUTH_END]) .try_into() @@ -115,7 +115,7 @@ impl DefragBuffer { return Err(e); } - let expiration_time = current_time + App::SETTINGS.fragment_assembly_timeout as i64; + let expiration_time = current_time + App::Crypto::SETTINGS.fragment_assembly_timeout as i64; let mut map = self.fragment_map.borrow_mut(); match map.entry(n) { Entry::Occupied(mut entry) => { @@ -157,7 +157,7 @@ impl DefragBuffer { } } - pub fn service(&self, current_time: i64) { + pub fn service(&self, current_time: i64) { let mut map = self.fragment_map.borrow_mut(); map.retain(|_, buffer| buffer.expiration_time < current_time); } diff --git a/src/log_event.rs b/src/log_event.rs index 3cb3948..ae01138 100644 --- a/src/log_event.rs +++ b/src/log_event.rs @@ -1,23 +1,23 @@ use std::sync::Arc; -use crate::application::ApplicationLayer; +use crate::application::CryptoLayer; use crate::Session; /// ZSSP events that might be interesting to log or aggregate into metrics. #[allow(missing_docs)] -pub enum LogEvent<'a, App: ApplicationLayer> { - ResentX1(&'a Arc>), - TimeoutX1(&'a Arc>), +pub enum LogEvent<'a, Crypto: CryptoLayer> { + ResentX1(&'a Arc>), + TimeoutX1(&'a Arc>), TimeoutX2, - ResentX3(&'a Arc>), - TimeoutX3(&'a Arc>), - ResentKeyConfirm(&'a Arc>), - TimeoutKeyConfirm(&'a Arc>), - StartedRekeyingSentK1(&'a Arc>), - ResentK1(&'a Arc>), - TimeoutK1(&'a Arc>), - ResentK2(&'a Arc>), - TimeoutK2(&'a Arc>), + ResentX3(&'a Arc>), + TimeoutX3(&'a Arc>), + ResentKeyConfirm(&'a Arc>), + TimeoutKeyConfirm(&'a Arc>), + StartedRekeyingSentK1(&'a Arc>), + ResentK1(&'a Arc>), + TimeoutK1(&'a Arc>), + ResentK2(&'a Arc>), + TimeoutK2(&'a Arc>), /// `(packet_type, packet_counter, fragment_no, fragment_count)` ReceivedRawFragment(u8, u64, usize, usize), ReceivedRawX1, @@ -25,24 +25,24 @@ pub enum LogEvent<'a, App: ApplicationLayer> { X1SucceededChallenge, X1IsAuthSentX2, ReceivedRawChallenge, - ChallengeIsAuth(&'a Arc>), + ChallengeIsAuth(&'a Arc>), ReceivedRawX2, - X2IsAuthSentX3(&'a Arc>), + X2IsAuthSentX3(&'a Arc>), ReceivedRawX3, - X3IsAuthSentKeyConfirm(&'a Arc>), + X3IsAuthSentKeyConfirm(&'a Arc>), ReceivedRawKeyConfirm, - KeyConfirmIsAuthSentAck(&'a Arc>), + KeyConfirmIsAuthSentAck(&'a Arc>), ReceivedRawAck, - AckIsAuth(&'a Arc>), + AckIsAuth(&'a Arc>), ReceivedRawK1, - K1IsAuthSentK2(&'a Arc>), + K1IsAuthSentK2(&'a Arc>), ReceivedRawK2, - K2IsAuthSentKeyConfirm(&'a Arc>), + K2IsAuthSentKeyConfirm(&'a Arc>), ReceivedRawD, - DIsAuthClosedSession(&'a Arc>), + DIsAuthClosedSession(&'a Arc>), } -impl<'a, App: ApplicationLayer> std::fmt::Debug for LogEvent<'a, App> { +impl<'a, Crypto: CryptoLayer> std::fmt::Debug for LogEvent<'a, Crypto> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ResentX1(_) => f.debug_tuple("ResentX1").finish(), diff --git a/src/result.rs b/src/result.rs index a3abb60..47da452 100644 --- a/src/result.rs +++ b/src/result.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use crate::application::ApplicationLayer; +use crate::application::CryptoLayer; use crate::Session; /// An error that can occur when attempting to open a session. @@ -121,13 +121,13 @@ pub(crate) use byzantine_fault; /// Result generated by the context packet receive function, with possible payloads. #[derive(Clone)] -pub enum ReceiveOk { +pub enum ReceiveOk { /// Packet superficially appeared valid but is not associated with a session yet. /// This can occur because the packet was only a fragment of a larger packet, /// or if it was a control packet that does not go through full Noise authentication. Unassociated, /// Packet was authentic and belongs to this specific session. - Session(Arc>, SessionEvent), + Session(Arc>, SessionEvent), } /// Something that can occur to an associated session when a packet is received successfully, /// including receiving a payload of decrypted, authenticated data. diff --git a/src/symmetric_state.rs b/src/symmetric_state.rs index 5388e8a..e061efb 100644 --- a/src/symmetric_state.rs +++ b/src/symmetric_state.rs @@ -2,19 +2,19 @@ use std::marker::PhantomData; use zeroize::Zeroizing; -use crate::application::ApplicationLayer; +use crate::application::CryptoLayer; use crate::crypto::*; use crate::proto::*; -pub struct SymmetricState { +pub struct SymmetricState { k: Zeroizing<[u8; AES_256_KEY_SIZE]>, ck: Zeroizing<[u8; HASHLEN]>, h: [u8; HASHLEN], - /// If anyone knows a better way to get rid of the "parameter `App` is never used" error please - /// let me know. - _app: PhantomData App::SessionData>, + /// If anyone knows a better way to get rid of the "parameter `Crypto` is never used" error + /// please let me know. + _app: PhantomData Crypto::SessionData>, } -impl Clone for SymmetricState { +impl Clone for SymmetricState { fn clone(&self) -> Self { Self { k: self.k.clone(), @@ -25,7 +25,7 @@ impl Clone for SymmetricState { } } -impl SymmetricState { +impl SymmetricState { /// HMAC-SHA512 key derivation based on KBKDF Counter Mode: /// https://csrc.nist.gov/publications/detail/sp/800-108/rev-1/final. /// Cryptographically this isn't meaningfully different from @@ -55,18 +55,18 @@ impl SymmetricState { buffer.extend(&(num_outputs * 8 * HASHLEN as u16).to_be_bytes()); debug_assert!(num_outputs >= 1); - *output1 = App::Hash::hmac(input_key_material, &buffer); + *output1 = Crypto::Hash::hmac(input_key_material, &buffer); if let Some(output2) = output2 { debug_assert!(num_outputs >= 2); buffer[0] = 2; - *output2 = App::Hash::hmac(input_key_material, &buffer); + *output2 = Crypto::Hash::hmac(input_key_material, &buffer); } if let Some(output3) = output3 { debug_assert!(num_outputs >= 3); buffer[0] = 3; - *output3 = App::Hash::hmac(input_key_material, &buffer); + *output3 = Crypto::Hash::hmac(input_key_material, &buffer); } } @@ -98,7 +98,7 @@ impl SymmetricState { } /// Corresponds to Noise `MixHash`. pub fn mix_hash(&mut self, data: &[u8]) { - let mut hash = App::Hash::new(); + let mut hash = Crypto::Hash::new(); hash.update(&self.h); hash.update(data); self.h = hash.finish(); @@ -129,7 +129,7 @@ impl SymmetricState { plaintext_start: usize, buffer: &mut Vec, ) { - let tag = App::Aead::encrypt_in_place(&self.k, &iv, Some(&self.h), &mut buffer[plaintext_start..]); + let tag = Crypto::Aead::encrypt_in_place(&self.k, &iv, Some(&self.h), &mut buffer[plaintext_start..]); buffer.extend(&tag); self.mix_hash(&buffer[plaintext_start..]); } @@ -141,11 +141,11 @@ impl SymmetricState { buffer: &mut [u8], tag: [u8; AES_GCM_TAG_SIZE], ) -> bool { - let mut hash = App::Hash::new(); + let mut hash = Crypto::Hash::new(); hash.update(&self.h); hash.update(buffer); hash.update(&tag); - let ret = App::Aead::decrypt_in_place(&self.k, &iv, Some(&self.h), buffer, &tag); + let ret = Crypto::Aead::decrypt_in_place(&self.k, &iv, Some(&self.h), buffer, &tag); self.h = hash.finish(); ret } diff --git a/src/zeta.rs b/src/zeta.rs index abad602..7e8a25c 100644 --- a/src/zeta.rs +++ b/src/zeta.rs @@ -7,7 +7,7 @@ use std::sync::{Arc, Weak}; use rand_core::RngCore; use zeroize::Zeroizing; -use crate::application::{ApplicationLayer, RatchetState, RatchetStates, RatchetUpdate}; +use crate::application::{ApplicationLayer, RatchetState, RatchetStates, RatchetUpdate, CryptoLayer}; use crate::challenge::{gen_null_response, respond_to_challenge_in_place}; use crate::context::{log, ContextInner, SessionMap}; use crate::crypto::*; @@ -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: App::SessionData, + pub session_data: Crypto::SessionData, /// Is true if the local peer acted as Bob, the responder in the initial key exchange. pub was_bob: bool, - s_remote: App::PublicKey, + s_remote: Crypto::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: App::KeyPair, - noise: SymmetricState, + e_secret: Crypto::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: App::KeyPair, - e1_secret: App::Kem, +pub(crate) struct StateA1 { + noise: SymmetricState, + e_secret: Crypto::KeyPair, + e1_secret: Crypto::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: App::KeyPair, + noise: SymmetricState, + e_secret: Crypto::KeyPair, k1: Vec, }, R2 { @@ -106,24 +106,24 @@ pub(crate) enum ZetaAutomata { }, } -impl SymmetricState { - fn write_e(&mut self, rng: &RefCell, packet: &mut Vec) -> App::KeyPair { - let e_secret = App::KeyPair::generate(rng.borrow_mut().deref_mut()); +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()); 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; - App::PublicKey::from_bytes((pub_key).try_into().unwrap()) + Crypto::PublicKey::from_bytes((pub_key).try_into().unwrap()) } - fn mix_dh(&mut self, secret: &App::KeyPair, remote: &App::PublicKey) -> Option<()> { + fn mix_dh(&mut self, secret: &Crypto::KeyPair, remote: &Crypto::PublicKey) -> Option<()> { if let Some(ecdh) = secret.agree(&remote).map(Zeroizing::new) { self.mix_key(ecdh.as_ref()); Some(()) @@ -165,11 +165,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)) { @@ -182,7 +182,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); @@ -235,23 +235,23 @@ impl Zeta { c, c >= self .key_creation_counter - .saturating_add(App::SETTINGS.rekey_after_key_uses), + .saturating_add(Crypto::SETTINGS.rekey_after_key_uses), )) } } fn create_a1_state( - rng: &RefCell, - s_remote: &App::PublicKey, + rng: &RefCell<::Rng>, + s_remote: &::PublicKey, kid_recv: NonZeroU32, ratchet_state1: &RatchetState, ratchet_state2: Option<&RatchetState>, identity: Vec, -) -> Option> { +) -> Option> { // <- 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(); @@ -264,7 +264,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) = App::Kem::generate(rng.borrow_mut().deref_mut()); + let (e1_secret, e1_public) = ::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. @@ -291,12 +291,12 @@ fn create_a1_state( /// Corresponds to Transition Algorithm 1 found in Section 4.3. pub(crate) fn trans_to_a1( mut app: App, - ctx: &Arc>, - s_remote: App::PublicKey, - session_data: App::SessionData, + ctx: &Arc>, + s_remote: ::PublicKey, + session_data: ::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))?; @@ -305,7 +305,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) .ok_or(OpenError::InvalidPublicKey)?; let packet = a1.packet.clone(); @@ -326,8 +326,8 @@ pub(crate) fn trans_to_a1( ratchet_state1: state1, ratchet_state2: state2, hk_send, - resend_timer: current_time + App::SETTINGS.resend_time as i64, - timeout_timer: current_time + App::SETTINGS.initial_offer_timeout as i64, + resend_timer: current_time + ::SETTINGS.resend_time as i64, + timeout_timer: current_time + ::SETTINGS.initial_offer_timeout as i64, beta: ZetaAutomata::A1(a1), }; zeta.key_mut(true).recv.kid = Some(kid_recv); @@ -344,13 +344,13 @@ pub(crate) fn trans_to_a1( } /// Corresponds to Algorithm 13 found in Section 5. pub(crate) fn respond_to_challenge( - zeta: &mut Zeta, - rng: &RefCell, + zeta: &mut Zeta, + rng: &RefCell<::Rng>, 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::( + respond_to_challenge_in_place::<::Rng, ::Hash>( rng.borrow_mut().deref_mut(), challenge, (&mut x1[response_start..]).try_into().unwrap(), @@ -360,7 +360,7 @@ pub(crate) fn respond_to_challenge( /// Corresponds to Transition Algorithm 2 found in Section 4.3. 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]), @@ -376,7 +376,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; @@ -441,7 +441,7 @@ pub(crate) fn received_x1_trans( .ok_or(byzantine_fault!(FailedAuth, true))?; // Process message pattern 2 ekem1 token. let i = x2.len(); - let (ekem1, ekem1_secret) = App::Kem::encapsulate( + let (ekem1, ekem1_secret) = ::Kem::encapsulate( ctx.rng.borrow_mut().deref_mut(), (&x1[e1_start..e1_end]).try_into().unwrap(), ) @@ -489,10 +489,10 @@ pub(crate) fn received_x1_trans( } /// Corresponds to Transition Algorithm 3 found in Section 4.3. pub(crate) fn received_x2_trans( - zeta: &mut Zeta, - session: &Arc>, + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - ctx: &Arc>, + ctx: &Arc>, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], mut x2: Vec, @@ -547,7 +547,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. @@ -632,8 +632,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 + App::SETTINGS.resend_time as i64; - zeta.timeout_timer = current_time + App::SETTINGS.initial_offer_timeout as i64; + zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + ::SETTINGS.initial_offer_timeout as i64; let packet = Packet(kid_send.get(), n, x3); zeta.beta = ZetaAutomata::A3 { identity, packet: packet.clone() }; @@ -653,7 +653,7 @@ pub(crate) fn received_x2_trans( result.map(|_| should_warn_missing_ratchet) } fn send_control( - zeta: &mut Zeta, + zeta: &mut Zeta, packet_type: u8, mut payload: Vec, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), @@ -661,7 +661,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 = App::Aead::encrypt_in_place(kek, &nonce, None, &mut payload); + let tag = ::Aead::encrypt_in_place(kek, &nonce, None, &mut payload); payload.extend(tag); send(&Packet(kid.get(), nonce, payload), Some(&zeta.hk_send)); @@ -675,13 +675,13 @@ fn send_control( } /// Corresponds to Transition Algorithm 4 found in Section 4.3. pub(crate) fn received_x3_trans( - zeta: StateB2, + 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()) { @@ -701,7 +701,7 @@ pub(crate) fn received_x3_trans( return Err(byzantine_fault!(FailedAuth, true)); } let s_remote = - App::PublicKey::from_bytes((&x3[i..j]).try_into().unwrap()).ok_or(byzantine_fault!(FailedAuth, true))?; + ::PublicKey::from_bytes((&x3[i..j]).try_into().unwrap()).ok_or(byzantine_fault!(FailedAuth, true))?; i = k; // Process message pattern 3 se token. noise @@ -727,7 +727,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 = App::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); + let tag = ::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 @@ -772,7 +772,7 @@ pub(crate) fn received_x3_trans( let mut c1 = Vec::new(); let n = to_nonce(PACKET_TYPE_KEY_CONFIRM, c); - let tag = App::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); + let tag = ::Aead::encrypt_in_place(&kek_send, &n, None, &mut []); c1.extend(&tag); let (nk1, nk2) = noise.split(); @@ -802,8 +802,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 + App::SETTINGS.resend_time as i64, - timeout_timer: current_time + App::SETTINGS.rekey_timeout as i64, + resend_timer: current_time + ::SETTINGS.resend_time as i64, + timeout_timer: current_time + ::SETTINGS.rekey_timeout as i64, beta: ZetaAutomata::S1, counter_antireplay_window: std::array::from_fn(|_| 0), defrag: zeta.defrag, @@ -827,9 +827,9 @@ 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, + zeta: &mut Zeta, app: &mut App, - rng: &RefCell, + rng: &RefCell<::Rng>, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], c1: Vec, @@ -857,7 +857,7 @@ pub(crate) fn received_c1_trans( .as_ref() .ok_or(byzantine_fault!(OutOfSequence, true))?; let tag = c1[..].try_into().unwrap(); - if !App::Aead::decrypt_in_place(specified_key, &n, None, &mut [], tag) { + if !::Aead::decrypt_in_place(specified_key, &n, None, &mut [], tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -887,14 +887,14 @@ pub(crate) fn received_c1_trans( zeta.ratchet_state2 = None; zeta.key_index ^= true; - let r = rng.borrow_mut().next_u64() % App::SETTINGS.rekey_time_max_jitter; - zeta.timeout_timer = app.time() + App::SETTINGS.rekey_after_time.saturating_sub(r) as i64; + 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; 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)); } @@ -903,9 +903,9 @@ 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, + zeta: &mut Zeta, app: &mut App, - rng: &RefCell, + rng: &RefCell<::Rng>, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], c2: Vec, @@ -925,7 +925,7 @@ pub(crate) fn received_c2_trans( } let tag = c2[..].try_into().unwrap(); - if !App::Aead::decrypt_in_place(zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, &mut [], tag) { + if !::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); @@ -933,8 +933,8 @@ pub(crate) fn received_c2_trans( return Err(byzantine_fault!(ExpiredCounter, true)); } - let r = rng.borrow_mut().next_u64() % App::SETTINGS.rekey_time_max_jitter; - zeta.timeout_timer = app.time() + App::SETTINGS.rekey_after_time.saturating_sub(r) as i64; + 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; zeta.resend_timer = i64::MAX; zeta.beta = ZetaAutomata::S2; Ok(()) @@ -942,7 +942,7 @@ pub(crate) fn received_c2_trans( /// 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, + zeta: &mut Zeta, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], d: Vec, @@ -957,7 +957,7 @@ pub(crate) fn received_d_trans( } let tag = d[..].try_into().unwrap(); - if !App::Aead::decrypt_in_place(zeta.key_ref(true).recv.kek.as_ref().unwrap(), &n, None, &mut [], tag) { + if !::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); @@ -970,9 +970,9 @@ pub(crate) fn received_d_trans( } /// 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>, + zeta: &mut Zeta, + session: &Arc>, + ctx: &Arc>, app: &mut App, current_time: i64, send: impl FnOnce(&Packet, Option<&[u8; AES_256_KEY_SIZE]>), @@ -981,7 +981,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 + App::SETTINGS.resend_time as i64; + zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; let (p, control_payload) = match &zeta.beta { ZetaAutomata::Null => return, @@ -1008,15 +1008,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>, + 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]>), ) { @@ -1030,7 +1030,7 @@ fn timeout_trans( } let new_kid_recv = remap(session, &zeta, &ctx.rng, &ctx.session_map); - if let Some(a1) = create_a1_state( + if let Some(a1) = create_a1_state::( &ctx.rng, &zeta.s_remote, new_kid_recv, @@ -1044,8 +1044,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 + App::SETTINGS.resend_time as i64; - zeta.timeout_timer = current_time + App::SETTINGS.initial_offer_timeout as i64; + zeta.resend_timer = current_time + ::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + ::SETTINGS.initial_offer_timeout as i64; zeta.beta = ZetaAutomata::A1(a1); zeta.defrag = DefragBuffer::new(Some(hk_recv)); @@ -1087,11 +1087,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 + App::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + App::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + ::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)); @@ -1109,12 +1109,12 @@ fn timeout_trans( } /// Corresponds to Transition Algorithm 7 found in Section 4.3. pub(crate) fn received_k1_trans( - zeta: &mut Zeta, - session: &Arc>, + zeta: &mut Zeta, + session: &Arc>, app: &mut App, - rng: &RefCell, - session_map: &SessionMap, - s_secret: &App::KeyPair, + rng: &RefCell<::Rng>, + session_map: &SessionMap, + s_secret: &::KeyPair, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], mut k1: Vec, @@ -1145,7 +1145,7 @@ pub(crate) fn received_k1_trans( let i = k1.len() - AES_GCM_TAG_SIZE; let tag = k1[i..].try_into().unwrap(); - if !App::Aead::decrypt_in_place( + if !::Aead::decrypt_in_place( zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, @@ -1162,7 +1162,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()); @@ -1234,11 +1234,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 + App::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + App::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + ::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 { .. })) { @@ -1248,7 +1248,7 @@ pub(crate) fn received_k1_trans( } /// Corresponds to Transition Algorithm 8 found in Section 4.3. pub(crate) fn received_k2_trans( - zeta: &mut Zeta, + zeta: &mut Zeta, app: &mut App, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], @@ -1271,7 +1271,7 @@ pub(crate) fn received_k2_trans( let i = k2.len() - AES_GCM_TAG_SIZE; let tag = k2[i..].try_into().unwrap(); - if !App::Aead::decrypt_in_place( + if !::Aead::decrypt_in_place( zeta.key_ref(false).recv.kek.as_ref().unwrap(), &n, None, @@ -1337,12 +1337,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 + App::SETTINGS.rekey_timeout as i64; - zeta.resend_timer = current_time + App::SETTINGS.resend_time as i64; + zeta.timeout_timer = current_time + ::SETTINGS.rekey_timeout as i64; + zeta.resend_timer = current_time + ::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!() @@ -1354,8 +1354,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> { @@ -1377,7 +1377,7 @@ pub(crate) fn send_payload( } let n = to_nonce(PACKET_TYPE_DATA, c); - let tag = App::Aead::encrypt_in_place(zeta.key_ref(false).send.nk.as_ref().unwrap(), &n, None, &mut payload); + let tag = Crypto::Aead::encrypt_in_place(zeta.key_ref(false).send.nk.as_ref().unwrap(), &n, None, &mut payload); payload.extend(&tag); send( @@ -1392,7 +1392,7 @@ pub(crate) fn send_payload( } /// Corresponds to Algorithm 10 found in Section 4.3. pub(crate) fn received_payload_in_place( - zeta: &mut Zeta, + zeta: &mut Zeta, kid: NonZeroU32, n: [u8; AES_GCM_NONCE_SIZE], payload: &mut Vec, @@ -1416,7 +1416,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 !App::Aead::decrypt_in_place(specified_key, &n, None, &mut payload[..i], &tag) { + if !::Aead::decrypt_in_place(specified_key, &n, None, &mut payload[..i], &tag) { return Err(byzantine_fault!(FailedAuth, true)); } let (_, c) = from_nonce(&n); @@ -1430,7 +1430,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. @@ -1439,7 +1439,7 @@ impl Session { } } -impl Drop for Session { +impl Drop for Session { fn drop(&mut self) { self.expire(); }