Bladeren bron

Sketch of symmetric key negotiation.

Kestrel 2 jaren geleden
bovenliggende
commit
7f79efe8bf

+ 2 - 0
Cargo.lock

@@ -147,6 +147,7 @@ dependencies = [
  "byteorder",
  "digest",
  "rand_core 0.5.1",
+ "serde",
  "subtle",
  "zeroize",
 ]
@@ -803,6 +804,7 @@ checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077"
 dependencies = [
  "curve25519-dalek",
  "rand_core 0.5.1",
+ "serde",
  "zeroize",
 ]
 

+ 1 - 1
fleck/Cargo.toml

@@ -22,7 +22,7 @@ timerfd = "1.3.0"
 # crypto dependencies
 aes-gcm = "0.10.1"
 ed25519-dalek = { version = "1.0.1", features = ["serde"] }
-x25519-dalek = { version = "1.2.0" }
+x25519-dalek = { version = "1.2.0", features = ["serde"] }
 rand = { version = "0.7", features = ["getrandom"] }
 
 [dev-dependencies]

+ 1 - 0
fleck/src/fleck_core.rs

@@ -61,5 +61,6 @@ impl crate::service::Service for std::rc::Rc<CoreInitService> {
         api.add_service::<node::NodeService>();
         api.add_service::<discovery::LocalDiscovery>();
         api.add_service::<peer::PeerService>();
+        api.add_service::<crypto::SignPacket>();
     }
 }

+ 131 - 12
fleck/src/fleck_core/crypto.rs

@@ -1,3 +1,6 @@
+use std::{cell::RefCell, collections::HashMap};
+
+use aes_gcm::aes::cipher::BlockEncrypt;
 pub use ed25519_dalek::{Keypair, PublicKey, Signature, Signer};
 
 use crate::prelude::*;
@@ -12,18 +15,6 @@ pub enum TrustLevel {
 
 pub struct TrustDB {}
 
-pub struct KeyExchangeInitiate {}
-
-impl fleck_core::msg::MessageParams for KeyExchangeInitiate {
-    const NAME: &'static str = "KeyExchangeInitiate";
-    const ENCRYPTED: bool = false;
-}
-
-pub enum KeyExchange {
-    WaitForResponse(x25519_dalek::PublicKey),
-    Completed(SymmetricKey),
-}
-
 #[derive(serde::Serialize, serde::Deserialize, Default, Debug)]
 pub enum PacketHeader {
     #[default]
@@ -109,3 +100,131 @@ impl SignPacket {
         });
     }
 }
+
+#[derive(serde::Serialize, serde::Deserialize)]
+pub struct KeyExchange {
+    key: x25519_dalek::PublicKey,
+}
+
+impl fleck_core::msg::MessageParams for KeyExchange {
+    const NAME: &'static str = "KeyExchange";
+    const ENCRYPTED: bool = false;
+    const SIGNED: bool = true;
+}
+
+pub enum KeyExchangeState {
+    NoState,
+    Given(x25519_dalek::PublicKey),
+    WaitForResponse(x25519_dalek::EphemeralSecret),
+    Completed(x25519_dalek::PublicKey, SymmetricKey),
+}
+
+pub struct EncryptionService {
+    state: RefCell<HashMap<fleck_core::peer::Peer, KeyExchangeState>>,
+}
+
+impl Default for EncryptionService {
+    fn default() -> Self {
+        Self {
+            state: Default::default(),
+        }
+    }
+}
+
+impl Service for std::rc::Rc<EncryptionService> {
+    fn setup(&self, api: &crate::Fleck) {
+        api.channel::<fleck_core::node::NodeRegistrationChannel>().sub_ref(self, EncryptionService::new_node);
+        api.channel::<fleck_core::msg::MessageChannel<KeyExchange>>().sub_eat(self, EncryptionService::incoming);
+    }
+}
+
+impl EncryptionService {
+    fn new_node(&self, api: &crate::Fleck, node: &mut std::rc::Rc<fleck_core::node::Node>) {
+        match node.peer().as_ref() {
+            Some(peer) => self.begin_handshake(api, peer),
+            None => (),
+        }
+    }
+
+    fn begin_handshake(&self, api: &crate::Fleck, with: &fleck_core::peer::Peer) {
+        use rand::SeedableRng;
+        let mut csprng = rand::rngs::StdRng::from_entropy();
+        let secret = x25519_dalek::EphemeralSecret::new(&mut csprng);
+
+        // send notification with new secret
+        api.queue::<fleck_core::SendPacketChannel>(fleck_core::msg::Message::build(
+            KeyExchange {
+                key: x25519_dalek::PublicKey::from(&secret)
+            }
+        ));
+
+        let mut states = self.state.borrow_mut();
+        let state = states.remove(&with).unwrap_or(KeyExchangeState::NoState);
+        match state {
+            KeyExchangeState::NoState => {
+                states.insert(with.clone(), KeyExchangeState::WaitForResponse(secret));
+            },
+            KeyExchangeState::Given(pubkey) => {
+                let result = secret.diffie_hellman(&pubkey);
+
+                let sk = SymmetricKey {
+                    key: result.as_bytes()[0..16].try_into().unwrap(),
+                    nonce: result.as_bytes()[16..32].try_into().unwrap(),
+                };
+
+                states.insert(with.clone(), KeyExchangeState::Completed(pubkey, sk));
+            },
+            KeyExchangeState::WaitForResponse(secret) => {
+                states.insert(with.clone(), KeyExchangeState::WaitForResponse(secret));
+            },
+            KeyExchangeState::Completed(_pubkey, _symmetric_key) => {
+                log::error!("asked to begin handshake when already have a good encryption key?");
+            },
+        }
+    }
+
+    fn incoming(&self, api: &crate::Fleck, msg: (fleck_core::msg::Metadata, KeyExchange)) {
+        let mut states = self.state.borrow_mut();
+        let peer = msg.0.peer.expect("incoming KeyExchange should have a peer?");
+        // let state = states.entry(peer.clone()).or_insert(KeyExchangeState::NoState);
+        let state = states.remove(&peer).unwrap_or(KeyExchangeState::NoState);
+        match state {
+            KeyExchangeState::NoState => {
+                states.insert(peer.clone(), KeyExchangeState::Given(msg.1.key));
+
+                drop(states);
+                self.begin_handshake(api, &peer);
+            },
+            KeyExchangeState::Given(peer_pubkey) => {
+                if peer_pubkey != msg.1.key {
+                    log::info!("peer DH key changed!");
+                    states.insert(peer.clone(), KeyExchangeState::Given(msg.1.key));
+                }
+
+                drop(states);
+                self.begin_handshake(api, &peer);
+            },
+            KeyExchangeState::WaitForResponse(secret) => {
+                // key handshake is finished!
+                let result = secret.diffie_hellman(&msg.1.key);
+
+                let sk = SymmetricKey {
+                    key: result.as_bytes()[0..16].try_into().unwrap(),
+                    nonce: result.as_bytes()[16..32].try_into().unwrap(),
+                };
+
+                states.insert(peer.clone(), KeyExchangeState::Completed(msg.1.key, sk));
+            },
+            KeyExchangeState::Completed(peer_pubkey, _symmetric_key) => {
+                if peer_pubkey == msg.1.key {
+                    // it's a repeat, so nothing to do
+                    return;
+                }
+                // it's a new pubkey, so we want to restart the handshake
+                states.insert(peer.clone(), KeyExchangeState::Given(msg.1.key));
+                drop(states);
+                self.begin_handshake(api, &peer);
+            },
+        }
+    }
+}

+ 2 - 25
fleck/src/fleck_core/discovery.rs

@@ -42,28 +42,14 @@ impl LocalDiscovery {
         // this will automatically ignore self-messages because we already know the pubkey
         api.with_service(|ns: &fleck_core::NodeService| {
             if ns.node_by_pubkey(&discovery.pkey).is_none() {
-                // let node = fleck_core::Node::build_with_peer(.data.addr.unwrap());
+                ns.inform_of_peer(msg.0.peer.unwrap());
+                // let node = fleck_core::node::Node::build_with_peer(msg.0.peer);
                 // node.set_pubkey(discovery.pkey);
                 // nodes.inform_of(node);
             }
         });
     }
 
-    /*fn packet(&self, api: &crate::Fleck, pkt: fleck_core::msg::Message) -> Option<fleck_core::msg::Message> {
-        /*if let Some(discovery) = pkt.data.as_msg::<DiscoveryMsg>() {
-            log::trace!("received discovery message");
-
-            // this will automatically ignore self-messages because we already know the pubkey
-            api.with_service(|nodes: &fleck_core::Nodes| {
-                if nodes.node_by_pubkey(&discovery.pkey).is_none() {
-                    let node = fleck_core::Node::build_with_addr(pkt.data.addr.unwrap());
-                    node.set_pubkey(discovery.pkey);
-                    nodes.inform_of(node);
-                }
-            });
-        }*/
-    }*/
-
     fn process_major_tick(&self, api: &crate::Fleck, _: &mut ()) {
         for peer in self.targets.borrow().iter() {
             let msg = fleck_core::msg::Message::build(DiscoveryMsg {
@@ -75,14 +61,5 @@ impl LocalDiscovery {
 
             api.queue::<fleck_core::SendPacketChannel>(msg);
         }
-        /*api.queue::<fleck_core::SendPacketChannel>(FleckPacket {
-            addr: Some((*crate::io::MULTICAST_ADDRESS).into()),
-            data: None,
-            io_channel: Some(api.raw_io().local().clone()),
-            node: None,
-            msg: Some(crate::msg::Message::build(DiscoveryMsg {
-                pkey: api.with_service(|nodes: &fleck_core::Nodes| nodes.self_node().pubkey().unwrap().to_owned())
-            })),
-        });*/
     }
 }

+ 1 - 4
fleck/src/fleck_core/io.rs

@@ -194,10 +194,7 @@ impl UdpSocket {
             peer.clone()
         } else {
             let peer = super::peer::Peer {
-                data: Rc::new(super::peer::PeerData {
-                    address_info: super::peer::PeerAddress::Udp(*addr),
-                    io: rc.clone(),
-                }),
+                data: Rc::new(super::peer::PeerData::new(rc.clone(), super::peer::PeerAddress::Udp(*addr)))
             };
             peers.insert(*addr, peer.clone());
             peer

+ 11 - 7
fleck/src/fleck_core/node.rs

@@ -39,21 +39,21 @@ impl<'l, T> std::ops::Deref for InnerRef<'l, T> {
 
 #[derive(Default)]
 pub struct Node {
-    addr: Option<std::net::SocketAddr>,
+    peer: Option<fleck_core::peer::Peer>,
     pubkey: RefCell<Option<PublicKey>>,
     keypair: RefCell<Option<Keypair>>,
 }
 
 impl Node {
-    pub fn build_with_addr(addr: std::net::SocketAddr) -> Self {
+    pub fn build_with_peer(peer: fleck_core::peer::Peer) -> Self {
         Self {
-            addr: Some(addr),
+            peer: Some(peer),
             ..Default::default()
         }
     }
 
-    pub fn addr(&self) -> Option<std::net::SocketAddr> {
-        self.addr
+    pub fn peer(&self) -> Option<fleck_core::peer::Peer> {
+        self.peer.clone()
     }
 
     pub fn pubkey(&self) -> Option<InnerRef<'_, PublicKey>> {
@@ -129,12 +129,12 @@ impl NodeService {
             .map(|r| r.to_owned())
     }
 
-    // nodes we know the address of
+    // nodes we believe we can communicate with directly
     pub fn direct_neighbours(&self) -> Vec<Rc<Node>> {
         self.all_nodes
             .borrow()
             .iter()
-            .filter(|n| n.addr.is_some())
+            .filter(|n| n.peer.is_some())
             .map(|r| r.to_owned())
             .collect()
     }
@@ -143,6 +143,10 @@ impl NodeService {
         // TODO: check for duplicates here
         self.all_nodes.borrow_mut().push(Rc::new(node));
     }
+
+    pub fn inform_of_peer(&self, peer: fleck_core::peer::Peer) {
+        todo!()
+    }
 }
 
 impl Service for Rc<NodeService> {

+ 38 - 2
fleck/src/fleck_core/peer.rs

@@ -1,6 +1,6 @@
 //! Peer: someone we can communicate with directly
 
-use std::rc::Rc;
+use std::{rc::Rc, cell::Cell};
 
 use crate::prelude::*;
 
@@ -13,6 +13,27 @@ pub(crate) enum PeerAddress {
 pub(crate) struct PeerData {
     pub(crate) io: Rc<dyn super::io::FdHandler>,
     pub(crate) address_info: PeerAddress,
+    sequence_number: Cell<u64>,
+}
+
+impl PeerData {
+    pub(crate) fn new(io: Rc<dyn super::io::FdHandler>, address_info: PeerAddress) -> Self {
+        Self {
+            io,
+            address_info,
+            sequence_number: Cell::new(0),
+        }
+    }
+
+    pub(crate) fn next_sequence(&self) -> u64 {
+        let ret = self.sequence_number.get();
+        self.sequence_number.set(ret.wrapping_add(1));
+        ret
+    }
+
+    pub(crate) fn reset_sequence(&self, to: u64) {
+        self.sequence_number.set(to);
+    }
 }
 
 impl std::fmt::Debug for PeerData {
@@ -26,6 +47,22 @@ pub struct Peer {
     pub(crate) data: Rc<PeerData>,
 }
 
+impl std::hash::Hash for Peer {
+    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+        state.write_usize(Rc::as_ptr(&self.data) as usize);
+    }
+}
+
+impl PartialEq for Peer {
+    fn eq(&self, other: &Self) -> bool {
+        Rc::as_ptr(&self.data) == Rc::as_ptr(&other.data)
+    }
+}
+
+impl Eq for Peer {
+    fn assert_receiver_is_total_eq(&self) { }
+}
+
 #[derive(Default)]
 pub struct PeerService {}
 
@@ -47,7 +84,6 @@ impl PeerService {
             log::error!("Message got to dispatch with no peer selected?");
             return None;
         }
-        log::trace!("dispatching message to peer");
         let peer = msg.peer.clone().unwrap();
         peer.data.io.dispatch(api, msg);
 

+ 0 - 17
fleck/src/lib.rs

@@ -28,23 +28,6 @@ impl Fleck {
         res
     }
 
-    fn register_core_services(&self) {
-        // core I/O service
-        // initial outgoing/incoming/minor/major channels
-        // self.services.borrow_mut().create_io_channels();
-
-        // Node registration
-        // self.add_service::<fleck_core::Nodes>();
-        // Local node discovery
-        // self.add_service::<fleck_core::lowlevel::LocalDiscovery>();
-        // Actually sending packets
-        // self.add_service::<fleck_core::lowlevel::SendPacket>();
-        // Parsing incoming packets
-        // self.add_service::<fleck_core::msg::ParsePacket>();
-        // Signing packets
-        // self.add_service::<crypto::SignPacket>();
-    }
-
     pub fn run(&self) {
         self.with_service(|io: &fleck_core::io::IOService| {
             io.run(self);