Added ability to remove peer from device

This commit is contained in:
Mathias Hall-Andersen
2019-07-26 22:36:24 +02:00
parent 97e5e1eacc
commit 59190dff33
2 changed files with 46 additions and 33 deletions

View File

@@ -13,11 +13,10 @@ use crate::peer::Peer;
use crate::types::*; use crate::types::*;
pub struct Device<T> { pub struct Device<T> {
pub sk: StaticSecret, // static secret key pub sk: StaticSecret, // static secret key
pub pk: PublicKey, // static public key pub pk: PublicKey, // static public key
peers: Vec<Peer<T>>, // peer index -> state pk_map: HashMap<[u8; 32], Peer<T>>, // public key -> peer state
pk_map: HashMap<[u8; 32], usize>, // public key -> peer index id_map: RwLock<HashMap<u32, [u8; 32]>>, // receiver ids -> public key
id_map: RwLock<HashMap<u32, usize>>, // receive ids -> peer index
} }
/* A mutable reference to the device needs to be held during configuration. /* A mutable reference to the device needs to be held during configuration.
@@ -36,7 +35,6 @@ where
Device { Device {
pk: PublicKey::from(&sk), pk: PublicKey::from(&sk),
sk: sk, sk: sk,
peers: vec![],
pk_map: HashMap::new(), pk_map: HashMap::new(),
id_map: RwLock::new(HashMap::new()), id_map: RwLock::new(HashMap::new()),
} }
@@ -66,14 +64,35 @@ where
// map : pk -> new index // map : pk -> new index
let idx = self.peers.len(); self.pk_map.insert(
self.pk_map.insert(*pk.as_bytes(), idx); *pk.as_bytes(),
Peer::new(identifier, pk, self.sk.diffie_hellman(&pk)),
);
// map : new index -> peer Ok(())
}
self.peers /// Remove a peer by public key
.push(Peer::new(idx, identifier, pk, self.sk.diffie_hellman(&pk))); /// To remove public keys, you must create a new machine instance
///
/// # Arguments
///
/// * `pk` - The public key of the peer to remove
///
/// # Returns
///
/// The call might fail if the public key is not found
pub fn remove(&mut self, pk: PublicKey) -> Result<(), ConfigError> {
// take write-lock on receive id table
let mut id_map = self.id_map.write();
// remove the peer
self.pk_map
.remove(pk.as_bytes())
.ok_or(ConfigError::new("Public key not in device"))?;
// pruge the id map (linear scan)
id_map.retain(|_, v| v != pk.as_bytes());
Ok(()) Ok(())
} }
@@ -88,9 +107,8 @@ where
/// ///
/// The call might fail if the public key is not found /// The call might fail if the public key is not found
pub fn psk(&mut self, pk: PublicKey, psk: Option<Psk>) -> Result<(), ConfigError> { pub fn psk(&mut self, pk: PublicKey, psk: Option<Psk>) -> Result<(), ConfigError> {
match self.pk_map.get(pk.as_bytes()) { match self.pk_map.get_mut(pk.as_bytes()) {
Some(&idx) => { Some(mut peer) => {
let peer = &mut self.peers[idx];
peer.psk = match psk { peer.psk = match psk {
Some(v) => v, Some(v) => v,
None => [0u8; 32], None => [0u8; 32],
@@ -120,9 +138,8 @@ where
pub fn begin(&self, pk: &PublicKey) -> Result<Vec<u8>, HandshakeError> { pub fn begin(&self, pk: &PublicKey) -> Result<Vec<u8>, HandshakeError> {
match self.pk_map.get(pk.as_bytes()) { match self.pk_map.get(pk.as_bytes()) {
None => Err(HandshakeError::UnknownPublicKey), None => Err(HandshakeError::UnknownPublicKey),
Some(&idx) => { Some(peer) => {
let peer = &self.peers[idx]; let sender = self.allocate(peer);
let sender = self.allocate(idx);
noise::create_initiation(self, peer, sender) noise::create_initiation(self, peer, sender)
} }
} }
@@ -140,7 +157,7 @@ where
let (peer, st) = noise::consume_initiation(self, msg)?; let (peer, st) = noise::consume_initiation(self, msg)?;
// allocate new index for response // allocate new index for response
let sender = self.allocate(peer.idx); let sender = self.allocate(peer);
// create response (release id on error) // create response (release id on error)
noise::create_response(peer, sender, st).map_err(|e| { noise::create_response(peer, sender, st).map_err(|e| {
@@ -157,26 +174,27 @@ where
// //
// Return the peer associated with the public key // Return the peer associated with the public key
pub(crate) fn lookup_pk(&self, pk: &PublicKey) -> Result<&Peer<T>, HandshakeError> { pub(crate) fn lookup_pk(&self, pk: &PublicKey) -> Result<&Peer<T>, HandshakeError> {
match self.pk_map.get(pk.as_bytes()) { self.pk_map
Some(&idx) => Ok(&self.peers[idx]), .get(pk.as_bytes())
_ => Err(HandshakeError::UnknownPublicKey), .ok_or(HandshakeError::UnknownPublicKey)
}
} }
// Internal function // Internal function
// //
// Return the peer currently associated with the receiver identifier // Return the peer currently associated with the receiver identifier
pub(crate) fn lookup_id(&self, id: u32) -> Result<&Peer<T>, HandshakeError> { pub(crate) fn lookup_id(&self, id: u32) -> Result<&Peer<T>, HandshakeError> {
match self.id_map.read().get(&id) { let im = self.id_map.read();
Some(&idx) => Ok(&self.peers[idx]), let pk = im.get(&id).ok_or(HandshakeError::UnknownReceiverId)?;
_ => Err(HandshakeError::UnknownReceiverId), match self.pk_map.get(pk) {
Some(peer) => Ok(peer),
_ => unreachable!(), // if the id-lookup succeeded, the peer should exist
} }
} }
// Internal function // Internal function
// //
// Allocated a new receiver identifier for the peer index // Allocated a new receiver identifier for the peer
fn allocate(&self, idx: usize) -> u32 { fn allocate(&self, peer: &Peer<T>) -> u32 {
let mut rng = OsRng::new().unwrap(); let mut rng = OsRng::new().unwrap();
loop { loop {
@@ -190,7 +208,7 @@ where
// take write lock and add index // take write lock and add index
let mut m = self.id_map.write(); let mut m = self.id_map.write();
if !m.contains_key(&id) { if !m.contains_key(&id) {
m.insert(id, idx); m.insert(id, *peer.pk.as_bytes());
return id; return id;
} }
} }

View File

@@ -20,9 +20,6 @@ pub struct Peer<T> {
// external identifier // external identifier
pub(crate) identifier: T, pub(crate) identifier: T,
// internal identifier
pub(crate) idx: usize,
// mutable state // mutable state
state: Mutex<State>, state: Mutex<State>,
timestamp: Mutex<Option<timestamp::TAI64N>>, timestamp: Mutex<Option<timestamp::TAI64N>>,
@@ -67,13 +64,11 @@ where
T: Copy, T: Copy,
{ {
pub fn new( pub fn new(
idx: usize,
identifier: T, // external identifier identifier: T, // external identifier
pk: PublicKey, // public key of peer pk: PublicKey, // public key of peer
ss: SharedSecret, // precomputed DH(static, static) ss: SharedSecret, // precomputed DH(static, static)
) -> Self { ) -> Self {
Self { Self {
idx: idx,
identifier: identifier, identifier: identifier,
state: Mutex::new(State::Reset), state: Mutex::new(State::Reset),
timestamp: Mutex::new(None), timestamp: Mutex::new(None),