use std::sync::Mutex; use generic_array::typenum::U32; use generic_array::GenericArray; use x25519_dalek::PublicKey; use x25519_dalek::StaticSecret; use x25519_dalek::SharedSecret; use crate::types::*; use crate::timestamp; use crate::device::Device; /* Represents the recomputation and state of a peer. * * This type is only for internal use and not exposed. */ pub struct Peer { // internal identifier pub(crate) idx : usize, // mutable state state : Mutex, timestamp : Mutex>, // constant state pub(crate) pk : PublicKey, // public key of peer pub(crate) ss : SharedSecret, // precomputed DH(static, static) pub(crate) psk : Psk // psk of peer } pub enum State { Reset, InitiationSent{ sender : u32, // assigned sender id eph_sk : StaticSecret, hs : GenericArray, ck : GenericArray }, } impl Clone for State { fn clone(&self) -> State { match self { State::Reset => State::Reset, State::InitiationSent{sender, eph_sk, hs, ck} => State::InitiationSent{ sender : *sender, eph_sk : StaticSecret::from(eph_sk.to_bytes()), hs : *hs, ck : *ck } } } } impl Peer { pub fn new( idx : usize, pk : PublicKey, // public key of peer ss : SharedSecret // precomputed DH(static, static) ) -> Self { Self { idx : idx, state : Mutex::new(State::Reset), timestamp : Mutex::new(None), pk : pk, ss : ss, psk : [0u8; 32] } } /// Return the state of the peer /// /// # Arguments pub fn get_state(&self) -> State { self.state.lock().unwrap().clone() } /// Set the state of the peer unconditionally /// /// # Arguments /// pub fn set_state( &self, state_new : State ) { let mut state = self.state.lock().unwrap(); *state = state_new; } /// Set the mutable state of the peer conditioned on the timestamp being newer /// /// # Arguments /// /// * st_new - The updated state of the peer /// * ts_new - The associated timestamp pub fn check_timestamp( &self, device : &Device, timestamp_new : ×tamp::TAI64N ) -> Result<(), HandshakeError> { let mut state = self.state.lock().unwrap(); let mut timestamp = self.timestamp.lock().unwrap(); let update = match *timestamp { None => true, Some(timestamp_old) => if timestamp::compare(×tamp_old, ×tamp_new) { true } else { false } }; if update { // release existing identifier match *state { State::InitiationSent{sender, ..} => { device.release(sender) }, _ => () } // reset state and update timestamp *state = State::Reset; *timestamp = Some(*timestamp_new); Ok(()) } else { Err(HandshakeError::OldTimestamp) } } }