From eb6a37144a2bf79d0db3793a428fc04454d4b75b Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Tue, 11 Feb 2020 20:36:34 -0800 Subject: [PATCH 01/96] build scaffold for handshake module substitution support --- lightning/src/ln/mod.rs | 4 +- lightning/src/ln/peers/chacha.rs | 34 ++ lightning/src/ln/peers/conduit.rs | 173 +++++++++ lightning/src/ln/peers/handshake/acts.rs | 33 ++ lightning/src/ln/peers/handshake/hash.rs | 25 ++ lightning/src/ln/peers/handshake/mod.rs | 398 +++++++++++++++++++++ lightning/src/ln/peers/handshake/states.rs | 30 ++ lightning/src/ln/peers/handshake/tests.rs | 26 ++ lightning/src/ln/peers/hkdf.rs | 18 + lightning/src/ln/peers/mod.rs | 4 + 10 files changed, 744 insertions(+), 1 deletion(-) create mode 100644 lightning/src/ln/peers/chacha.rs create mode 100644 lightning/src/ln/peers/conduit.rs create mode 100644 lightning/src/ln/peers/handshake/acts.rs create mode 100644 lightning/src/ln/peers/handshake/hash.rs create mode 100644 lightning/src/ln/peers/handshake/mod.rs create mode 100644 lightning/src/ln/peers/handshake/states.rs create mode 100644 lightning/src/ln/peers/handshake/tests.rs create mode 100644 lightning/src/ln/peers/hkdf.rs create mode 100644 lightning/src/ln/peers/mod.rs diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 9a2a90fd4fd..8ff78e02077 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -13,6 +13,7 @@ pub mod channelmanager; pub mod channelmonitor; pub mod msgs; pub mod router; +pub mod peers; pub mod peer_handler; pub mod chan_utils; pub mod features; @@ -27,7 +28,8 @@ mod onion_utils; mod wire; #[cfg(test)] -#[macro_use] mod functional_test_utils; +#[macro_use] +mod functional_test_utils; #[cfg(test)] mod functional_tests; #[cfg(test)] diff --git a/lightning/src/ln/peers/chacha.rs b/lightning/src/ln/peers/chacha.rs new file mode 100644 index 00000000000..4b29b924388 --- /dev/null +++ b/lightning/src/ln/peers/chacha.rs @@ -0,0 +1,34 @@ +use util::chacha20poly1305rfc::ChaCha20Poly1305RFC; + +pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) -> Vec { + let mut nonce_bytes = [0; 12]; + nonce_bytes[4..].copy_from_slice(&nonce.to_le_bytes()); + + let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data); + let mut ciphertext = vec![0u8; plaintext.len()]; + let mut authentication_tag = [0u8; 16]; + chacha.encrypt(plaintext, &mut ciphertext, &mut authentication_tag); + + let mut tagged_ciphertext = ciphertext; + tagged_ciphertext.extend_from_slice(&authentication_tag); + tagged_ciphertext +} + + +pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext: &[u8]) -> Result, String> { + let mut nonce_bytes = [0; 12]; + nonce_bytes[4..].copy_from_slice(&nonce.to_le_bytes()); + + let length = tagged_ciphertext.len(); + let ciphertext = &tagged_ciphertext[0..length - 16]; + let authentication_tag = &tagged_ciphertext[length - 16..length]; + + let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data); + let mut plaintext = vec![0u8; length - 16]; + let success = chacha.decrypt(ciphertext, &mut plaintext, authentication_tag); + if success { + Ok(plaintext.to_vec()) + } else { + Err("invalid hmac".to_string()) + } +} diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs new file mode 100644 index 00000000000..fe1c5adcb90 --- /dev/null +++ b/lightning/src/ln/peers/conduit.rs @@ -0,0 +1,173 @@ +use ln::peers::{chacha, hkdf}; + +/// Returned after a successful handshake to encrypt and decrypt communication with peer nodes +pub struct Conduit { + pub(crate) sending_key: [u8; 32], + pub(crate) receiving_key: [u8; 32], + + pub(crate) sending_chaining_key: [u8; 32], + pub(crate) receiving_chaining_key: [u8; 32], + + pub(crate) receiving_nonce: u32, + pub(crate) sending_nonce: u32, + + pub(super) read_buffer: Option>, +} + +impl Conduit { + pub fn encrypt(&mut self, buffer: &[u8]) -> Vec { + let length = buffer.len() as u16; + let length_bytes = length.to_be_bytes(); + + let encrypted_length = chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes); + self.increment_sending_nonce(); + + let encrypted_message = chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer); + self.increment_sending_nonce(); + + let mut ciphertext = encrypted_length; + ciphertext.extend_from_slice(&encrypted_message); + ciphertext + } + + pub(super) fn read(&mut self, data: &[u8]) { + let mut read_buffer = if let Some(buffer) = self.read_buffer.take() { + buffer + } else { + Vec::new() + }; + + read_buffer.extend_from_slice(data); + self.read_buffer = Some(read_buffer); + } + + /// Add newly received data from the peer node to the buffer and decrypt all possible messages + pub fn decrypt_message_stream(&mut self, new_data: Option<&[u8]>) -> Vec> { + let mut read_buffer = if let Some(buffer) = self.read_buffer.take() { + buffer + } else { + Vec::new() + }; + + if let Some(data) = new_data { + read_buffer.extend_from_slice(data); + } + + let mut messages = Vec::new(); + + loop { + // todo: find way that won't require cloning the entire buffer + let (current_message, offset) = self.decrypt(&read_buffer[..]); + if offset == 0 { + break; + } + + read_buffer.drain(0..offset); + + if let Some(message) = current_message { + messages.push(message); + } else { + break; + } + } + + self.read_buffer = Some(read_buffer); + + messages + } + + /// Decrypt a single message. Buffer is an undelimited amount of bytes + fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { // the response slice should have the same lifetime as the argument. It's the slice data is read from + if buffer.len() < 18 { + return (None, 0); + } + + let encrypted_length = &buffer[0..18]; // todo: abort if too short + let length_vec = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap(); + let mut length_bytes = [0u8; 2]; + length_bytes.copy_from_slice(length_vec.as_slice()); + let message_length = u16::from_be_bytes(length_bytes) as usize; + + let message_end_index = message_length + 18; // todo: abort if too short + if buffer.len() < message_end_index { + return (None, 0); + } + + let encrypted_message = &buffer[18..message_end_index]; + + self.increment_receiving_nonce(); + + let message = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_message).unwrap(); + + self.increment_receiving_nonce(); + + (Some(message), message_end_index) + } + + fn increment_sending_nonce(&mut self) { + Self::increment_nonce(&mut self.sending_nonce, &mut self.sending_chaining_key, &mut self.sending_key); + } + + fn increment_receiving_nonce(&mut self) { + Self::increment_nonce(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); + } + + fn increment_nonce(nonce: &mut u32, chaining_key: &mut [u8; 32], key: &mut [u8; 32]) { + *nonce += 1; + if *nonce == 1000 { + Self::rotate_key(chaining_key, key); + *nonce = 0; + } + } + + fn rotate_key(chaining_key: &mut [u8; 32], key: &mut [u8; 32]) { + let (new_chaining_key, new_key) = hkdf::derive(chaining_key, key); + chaining_key.copy_from_slice(&new_chaining_key); + key.copy_from_slice(&new_key); + } +} + +#[cfg(test)] +mod tests { + use ln::peers::conduit::Conduit; + + #[test] + fn test_chaining() { + let chaining_key_vec = hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap(); + let mut chaining_key = [0u8; 32]; + chaining_key.copy_from_slice(&chaining_key_vec); + + let sending_key_vec = hex::decode("969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9").unwrap(); + let mut sending_key = [0u8; 32]; + sending_key.copy_from_slice(&sending_key_vec); + + let receiving_key_vec = hex::decode("bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442").unwrap(); + let mut receiving_key = [0u8; 32]; + receiving_key.copy_from_slice(&receiving_key_vec); + + let mut connected_peer = Conduit { + sending_key, + receiving_key, + sending_chaining_key: chaining_key, + receiving_chaining_key: chaining_key, + sending_nonce: 0, + receiving_nonce: 0, + read_buffer: None, + }; + + let message = hex::decode("68656c6c6f").unwrap(); + let mut encrypted_messages: Vec> = Vec::new(); + + for _ in 0..1002 { + let encrypted_message = connected_peer.encrypt(&message); + encrypted_messages.push(encrypted_message); + } + + assert_eq!(encrypted_messages[0], hex::decode("cf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95").unwrap()); + assert_eq!(encrypted_messages[1], hex::decode("72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1").unwrap()); + assert_eq!(encrypted_messages[500], hex::decode("178cb9d7387190fa34db9c2d50027d21793c9bc2d40b1e14dcf30ebeeeb220f48364f7a4c68bf8").unwrap()); + assert_eq!(encrypted_messages[501], hex::decode("1b186c57d44eb6de4c057c49940d79bb838a145cb528d6e8fd26dbe50a60ca2c104b56b60e45bd").unwrap()); + assert_eq!(encrypted_messages[1000], hex::decode("4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09").unwrap()); + assert_eq!(encrypted_messages[1001], hex::decode("2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36").unwrap()); + } +} \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs new file mode 100644 index 00000000000..1a42e5dd430 --- /dev/null +++ b/lightning/src/ln/peers/handshake/acts.rs @@ -0,0 +1,33 @@ +pub struct ActOne( + pub(super) [u8; 50] +); + +pub struct ActTwo( + pub(super) [u8; 50] +); + +pub struct ActThree( + pub(super) [u8; 66] +); + +pub enum Act { + One(ActOne), + Two(ActTwo), + Three(ActThree), +} + +impl Act { + pub fn serialize(&self) -> Vec { + match self { + Act::One(act) => { + act.0.to_vec() + } + Act::Two(act) => { + act.0.to_vec() + } + Act::Three(act) => { + act.0.to_vec() + } + } + } +} \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/hash.rs b/lightning/src/ln/peers/handshake/hash.rs new file mode 100644 index 00000000000..0beef40fd93 --- /dev/null +++ b/lightning/src/ln/peers/handshake/hash.rs @@ -0,0 +1,25 @@ +use bitcoin_hashes::{Hash, HashEngine}; +use bitcoin_hashes::sha256::Hash as Sha256; + +pub(crate) struct HandshakeHash { + pub(super) value: [u8; 32] +} + +impl HandshakeHash { + pub(super) fn new(first_input: &[u8]) -> Self { + let mut hash = Self { + value: [0; 32] + }; + let mut sha = Sha256::engine(); + sha.input(first_input); + hash.value = Sha256::from_engine(sha).into_inner(); + hash + } + + pub(super) fn update(&mut self, input: &[u8]) { + let mut sha = Sha256::engine(); + sha.input(self.value.as_ref()); + sha.input(input); + self.value = Sha256::from_engine(sha).into_inner(); + } +} \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs new file mode 100644 index 00000000000..087f7ecfa73 --- /dev/null +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -0,0 +1,398 @@ +use bitcoin_hashes::{Hash, HashEngine}; +use bitcoin_hashes::sha256::Hash as Sha256; +use rand::{Rng, thread_rng}; +use secp256k1::{PublicKey, SecretKey}; + +use ln::peers::{chacha, hkdf}; +use ln::peers::conduit::Conduit; +use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo}; +use ln::peers::handshake::hash::HandshakeHash; +use ln::peers::handshake::states::{ActOneExpectation, ActThreeExpectation, ActTwoExpectation, HandshakeState}; + +mod acts; +mod hash; +mod states; +mod tests; + +pub struct PeerHandshake { + state: Option, + private_key: SecretKey, + + preset_ephemeral_private_key: Option, + read_buffer: Vec, +} + +impl PeerHandshake { + pub fn new(private_key: &SecretKey, ephemeral_private_key: Option<&SecretKey>) -> Self { + let preset_ephemeral_private_key = if let Some(key) = ephemeral_private_key { + // deref and clone + Some((*key).clone()) + } else { + None + }; + + let handshake = PeerHandshake { + state: Some(HandshakeState::Blank), + private_key: (*private_key).clone(), + preset_ephemeral_private_key, + read_buffer: Vec::new(), + }; + handshake + } + + pub fn make_inbound(&mut self) { + let public_key = Self::private_key_to_public_key(&self.private_key); + let (hash, chaining_key) = Self::initialize_state(&public_key); + self.state = Some(HandshakeState::AwaitingActOne(ActOneExpectation { + hash, + chaining_key, + })) + } + + fn initialize_state(public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { + // do the proper initialization + let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; + let prologue = b"lightning"; + + let mut sha = Sha256::engine(); + sha.input(protocol_name); + let chaining_key = Sha256::from_engine(sha).into_inner(); + + let mut initial_hash_preimage = chaining_key.to_vec(); + initial_hash_preimage.extend_from_slice(prologue.as_ref()); + + let mut hash = HandshakeHash::new(initial_hash_preimage.as_slice()); + hash.update(&public_key.serialize()); + + (hash, chaining_key) // hash, chaining_key + } + + /// Process act dynamically + /// The role must be set before this method can be called + pub fn process_act(&mut self, input: &[u8], remote_public_key: Option<&PublicKey>) -> Result<(Vec, Option, Option), String> { + let mut response: Vec = Vec::new(); + let mut connected_peer = None; + let mut remote_pubkey = None; + + self.read_buffer.extend_from_slice(input); + let read_buffer_length = self.read_buffer.len(); + + match &self.state { + Some(HandshakeState::Blank) => { + let remote_public_key = remote_public_key.ok_or("Call make_initiator() first")?; + let ephemeral_private_key = self.obtain_ephemeral_private_key(); + + let act_one = self.initiate(&ephemeral_private_key, &remote_public_key)?; + response = act_one.0.to_vec(); + } + Some(HandshakeState::AwaitingActOne(_)) => { + let act_length = 50; + if read_buffer_length < act_length { + return Err("need at least 50 bytes".to_string()); + } + + let mut act_one_buffer = [0u8; 50]; + act_one_buffer.copy_from_slice(&self.read_buffer[..act_length]); + self.read_buffer.drain(..act_length); + + let ephemeral_private_key = self.obtain_ephemeral_private_key(); + + let act_two = self.process_act_one(ActOne(act_one_buffer), &ephemeral_private_key)?; + response = act_two.0.to_vec(); + } + Some(HandshakeState::AwaitingActTwo(_)) => { + let act_length = 50; + if read_buffer_length < act_length { + return Err("need at least 50 bytes".to_string()); + } + + let mut act_two_buffer = [0u8; 50]; + act_two_buffer.copy_from_slice(&self.read_buffer[..act_length]); + self.read_buffer.drain(..act_length); + + let (act_three, mut conduit) = self.process_act_two(ActTwo(act_two_buffer))?; + + if self.read_buffer.len() > 0 { // have we received more data still? + conduit.read(&self.read_buffer[..]); + self.read_buffer.drain(..); + } + + response = act_three.0.to_vec(); + connected_peer = Some(conduit); + } + Some(HandshakeState::AwaitingActThree(_)) => { + let act_length = 66; + if read_buffer_length < act_length { + return Err("need at least 50 bytes".to_string()); + } + + let mut act_three_buffer = [0u8; 66]; + act_three_buffer.copy_from_slice(&self.read_buffer[..act_length]); + self.read_buffer.drain(..act_length); + + let (public_key, mut conduit) = self.process_act_three(ActThree(act_three_buffer))?; + + if self.read_buffer.len() > 0 { // have we received more data still? + conduit.read(&self.read_buffer[..]); + self.read_buffer.drain(..); + } + + connected_peer = Some(conduit); + remote_pubkey = Some(public_key); + } + _ => { + return Err("no acts left to process".to_string()); + } + }; + Ok((response, connected_peer, remote_pubkey)) + } + + pub fn initiate(&mut self, ephemeral_private_key: &SecretKey, remote_public_key: &PublicKey) -> Result { + if let Some(HandshakeState::Blank) = &self.state {} else { + return Err("incorrect state".to_string()); + } + + let (mut hash, chaining_key) = Self::initialize_state(&remote_public_key); + + // serialize act one + let (act_one, chaining_key, temporary_key) = self.calculate_act_message( + ephemeral_private_key, + remote_public_key, + chaining_key, + &mut hash, + ); + + self.state = Some(HandshakeState::AwaitingActTwo(ActTwoExpectation { + hash, + chaining_key, + temporary_key, + ephemeral_private_key: (*ephemeral_private_key).clone(), + })); + + Ok(ActOne(act_one)) + } + + pub(crate) fn process_act_one(&mut self, act: ActOne, ephemeral_private_key: &SecretKey) -> Result { + let state = self.state.take(); + let act_one_expectation = match state { + Some(HandshakeState::AwaitingActOne(act_state)) => act_state, + Some(HandshakeState::Blank) => { + // this can also be initiated from a blank state + // public key + let public_key = Self::private_key_to_public_key(&self.private_key); + let (hash, chaining_key) = Self::initialize_state(&public_key); + ActOneExpectation { + hash, + chaining_key, + } + } + _ => { + self.state = state; + return Err("unexpected state".to_string()); + } + }; + + let mut hash = act_one_expectation.hash; + let (remote_ephemeral_public_key, chaining_key, _) = self.process_act_message( + act.0, + &self.private_key, + act_one_expectation.chaining_key, + &mut hash, + )?; + + let (act_two, chaining_key, temporary_key) = self.calculate_act_message( + ephemeral_private_key, + &remote_ephemeral_public_key, + chaining_key, + &mut hash, + ); + + self.state = Some(HandshakeState::AwaitingActThree(ActThreeExpectation { + hash, + chaining_key, + temporary_key, + ephemeral_private_key: (*ephemeral_private_key).clone(), + remote_ephemeral_public_key, + })); + + Ok(ActTwo(act_two)) + } + + pub(crate) fn process_act_two(&mut self, act: ActTwo) -> Result<(ActThree, Conduit), String> { + let state = self.state.take(); + let act_two_expectation = match state { + Some(HandshakeState::AwaitingActTwo(act_state)) => act_state, + _ => { + self.state = state; + return Err("unexpected state".to_string()); + } + }; + + let mut hash = act_two_expectation.hash; + let (remote_ephemeral_public_key, chaining_key, temporary_key) = self.process_act_message( + act.0, + &act_two_expectation.ephemeral_private_key, + act_two_expectation.chaining_key, + &mut hash, + )?; + + self.state = Some(HandshakeState::Complete); + + // start serializing act three + + let static_public_key = Self::private_key_to_public_key(&self.private_key); + let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &static_public_key.serialize()); + hash.update(&tagged_encrypted_pubkey); + + let ecdh = Self::ecdh(&self.private_key, &remote_ephemeral_public_key); + let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); + let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); + + let mut act_three_vec = [0u8].to_vec(); + act_three_vec.extend_from_slice(&tagged_encrypted_pubkey); + act_three_vec.extend_from_slice(authentication_tag.as_slice()); + let mut act_three = [0u8; 66]; + act_three.copy_from_slice(act_three_vec.as_slice()); + + let connected_peer = Conduit { + sending_key, + receiving_key, + sending_chaining_key: chaining_key, + receiving_chaining_key: chaining_key, + sending_nonce: 0, + receiving_nonce: 0, + read_buffer: None, + }; + Ok((ActThree(act_three), connected_peer)) + } + + pub(crate) fn process_act_three(&mut self, act: ActThree) -> Result<(PublicKey, Conduit), String> { + let state = self.state.take(); + let act_three_expectation = match state { + Some(HandshakeState::AwaitingActThree(act_state)) => act_state, + _ => { + self.state = state; + return Err("unexpected state".to_string()); + } + }; + + let version = act.0[0]; + if version != 0 { + return Err("unexpected version".to_string()); + } + + let mut tagged_encrypted_pubkey = [0u8; 49]; + tagged_encrypted_pubkey.copy_from_slice(&act.0[1..50]); + + let mut chacha_tag = [0u8; 16]; + chacha_tag.copy_from_slice(&act.0[50..66]); + + let mut hash = act_three_expectation.hash; + + let remote_pubkey_vec = chacha::decrypt(&act_three_expectation.temporary_key, 1, &hash.value, &tagged_encrypted_pubkey)?; + let mut remote_pubkey_bytes = [0u8; 33]; + remote_pubkey_bytes.copy_from_slice(remote_pubkey_vec.as_slice()); + // todo: replace unwrap with handleable error type + let remote_pubkey = PublicKey::from_slice(&remote_pubkey_bytes).unwrap(); + + hash.update(&tagged_encrypted_pubkey); + + let ecdh = Self::ecdh(&act_three_expectation.ephemeral_private_key, &remote_pubkey); + let (chaining_key, temporary_key) = hkdf::derive(&act_three_expectation.chaining_key, &ecdh); + let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; + let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); + + let connected_peer = Conduit { + sending_key, + receiving_key, + sending_chaining_key: chaining_key, + receiving_chaining_key: chaining_key, + sending_nonce: 0, + receiving_nonce: 0, + read_buffer: None, + }; + Ok((remote_pubkey, connected_peer)) + } + + fn obtain_ephemeral_private_key(&mut self) -> SecretKey { + if let Some(key) = self.preset_ephemeral_private_key.take() { + key + } else { + // generate a random ephemeral private key right here + let mut rng = thread_rng(); + let mut ephemeral_bytes = [0; 32]; + rng.fill_bytes(&mut ephemeral_bytes); + SecretKey::from_slice(&ephemeral_bytes).expect("You broke elliptic curve cryptography") + } + } + + fn calculate_act_message(&self, local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], [u8; 32], [u8; 32]) { + let local_public_key = Self::private_key_to_public_key(local_private_key); + + hash.update(&local_public_key.serialize()); + + let ecdh = Self::ecdh(local_private_key, &remote_public_key); + let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); + + hash.update(&tagged_ciphertext); + + let mut act_vec = [0u8].to_vec(); + act_vec.extend_from_slice(&local_public_key.serialize()); + act_vec.extend_from_slice(tagged_ciphertext.as_slice()); + let mut act = [0u8; 50]; + act.copy_from_slice(act_vec.as_slice()); + (act, chaining_key, temporary_key) + } + + fn process_act_message(&self, act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> Result<(PublicKey, [u8; 32], [u8; 32]), String> { + let version = act_bytes[0]; + if version != 0 { + return Err("unexpected version".to_string()); + } + + let mut ephemeral_public_key_bytes = [0u8; 33]; + ephemeral_public_key_bytes.copy_from_slice(&act_bytes[1..34]); + // todo: replace unwrap with handleable error type + let ephemeral_public_key = PublicKey::from_slice(&ephemeral_public_key_bytes).unwrap(); + + let mut chacha_tag = [0u8; 16]; + chacha_tag.copy_from_slice(&act_bytes[34..50]); + + // process the act message + + // update hash with partner's pubkey + hash.update(&ephemeral_public_key.serialize()); + + // calculate ECDH with partner's pubkey and local privkey + let ecdh = Self::ecdh(local_private_key, &ephemeral_public_key); + + // HKDF(chaining key, ECDH) -> chaining key' + next temporary key + let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + + // Validate chacha tag (temporary key, 0, self.hash, chacha_tag) + let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; + + hash.update(&chacha_tag); + + Ok((ephemeral_public_key, chaining_key, temporary_key)) + } + + fn private_key_to_public_key(private_key: &SecretKey) -> PublicKey { + let curve = secp256k1::Secp256k1::new(); + let pk_object = PublicKey::from_secret_key(&curve, &private_key); + pk_object + } + + fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> [u8; 32] { + let curve = secp256k1::Secp256k1::new(); + let mut pk_object = public_key.clone(); + pk_object.mul_assign(&curve, &private_key[..]).expect("invalid multiplication"); + + let preimage = pk_object.serialize(); + let mut sha = Sha256::engine(); + sha.input(preimage.as_ref()); + Sha256::from_engine(sha).into_inner() + } +} \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs new file mode 100644 index 00000000000..836be023a0d --- /dev/null +++ b/lightning/src/ln/peers/handshake/states.rs @@ -0,0 +1,30 @@ +use ln::peers::handshake::hash::HandshakeHash; +use secp256k1::{SecretKey, PublicKey}; + +pub enum HandshakeState { + Blank, + AwaitingActOne(ActOneExpectation), + AwaitingActTwo(ActTwoExpectation), + AwaitingActThree(ActThreeExpectation), + Complete, +} + +pub struct ActOneExpectation { + pub(super) hash: HandshakeHash, + pub(super) chaining_key: [u8; 32], +} + +pub struct ActTwoExpectation { + pub(super) hash: HandshakeHash, + pub(super) chaining_key: [u8; 32], + pub(super) temporary_key: [u8; 32], + pub(super) ephemeral_private_key: SecretKey, +} + +pub struct ActThreeExpectation { + pub(super) hash: HandshakeHash, + pub(super) chaining_key: [u8; 32], + pub(super) temporary_key: [u8; 32], + pub(super) ephemeral_private_key: SecretKey, + pub(super) remote_ephemeral_public_key: PublicKey, +} \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/tests.rs b/lightning/src/ln/peers/handshake/tests.rs new file mode 100644 index 00000000000..48d89a9fde6 --- /dev/null +++ b/lightning/src/ln/peers/handshake/tests.rs @@ -0,0 +1,26 @@ +#![cfg(test)] + +use secp256k1::key::{PublicKey, SecretKey}; + +use ln::peers::handshake::PeerHandshake; + +#[test] +fn test_exchange() { + let curve = secp256k1::Secp256k1::new(); + + let local_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let remote_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + + let local_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); + let remote_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); + + let mut local_handshake = PeerHandshake::new(&local_private_key, Some(&local_ephemeral_private_key)); + let mut remote_handshake = PeerHandshake::new(&remote_private_key, Some(&remote_ephemeral_private_key)); + + let remote_public_key = PublicKey::from_secret_key(&curve, &remote_private_key); + + let act_1_message = local_handshake.initiate(&local_ephemeral_private_key, &remote_public_key); + let act_2_message = remote_handshake.process_act_one(act_1_message.unwrap(), &remote_ephemeral_private_key); + let act_3_message = local_handshake.process_act_two(act_2_message.unwrap()); + remote_handshake.process_act_three(act_3_message.unwrap().0).unwrap(); +} \ No newline at end of file diff --git a/lightning/src/ln/peers/hkdf.rs b/lightning/src/ln/peers/hkdf.rs new file mode 100644 index 00000000000..396515a4bf2 --- /dev/null +++ b/lightning/src/ln/peers/hkdf.rs @@ -0,0 +1,18 @@ +use bitcoin_hashes::{Hash, HashEngine, Hmac, HmacEngine}; +use bitcoin_hashes::sha256::Hash as Sha256; + +pub fn derive(salt: &[u8], master: &[u8]) -> ([u8; 32], [u8; 32]) { + let mut hmac = HmacEngine::::new(salt); + hmac.input(master); + let prk = Hmac::from_engine(hmac).into_inner(); // prk = sha256(master) + + let mut hmac = HmacEngine::::new(&prk[..]); + hmac.input(&[1; 1]); + let t1 = Hmac::from_engine(hmac).into_inner(); // t1 = sha256(prk | 1) + + let mut hmac = HmacEngine::::new(&prk[..]); + hmac.input(&t1); + hmac.input(&[2; 1]); + // sha256(prk | t1 | 2) = sha256(sha256(master) | sha256(sha256(sha256(master) | 1) | 2) + (t1, Hmac::from_engine(hmac).into_inner()) +} \ No newline at end of file diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs new file mode 100644 index 00000000000..748356a8f12 --- /dev/null +++ b/lightning/src/ln/peers/mod.rs @@ -0,0 +1,4 @@ +mod chacha; +pub mod conduit; +pub mod handshake; +mod hkdf; From b71b7ea4b27b1c1a7a68e2ca59e5819923462f70 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Tue, 11 Feb 2020 22:41:35 -0800 Subject: [PATCH 02/96] change peer_handler.rs to use modular handshake and encryption handler, and only expose old peer_channel_encryptor.rs to fuzz tests --- lightning/src/ln/mod.rs | 2 - lightning/src/ln/peer_handler.rs | 660 ++++++++++++------------ lightning/src/ln/peers/handshake/mod.rs | 2 +- 3 files changed, 337 insertions(+), 327 deletions(-) diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index 8ff78e02077..16bf959be87 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -20,8 +20,6 @@ pub mod features; #[cfg(feature = "fuzztarget")] pub mod peer_channel_encryptor; -#[cfg(not(feature = "fuzztarget"))] -pub(crate) mod peer_channel_encryptor; mod channel; mod onion_utils; diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 44d08030062..44f0214b0fc 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -13,7 +13,6 @@ use ln::msgs; use ln::msgs::ChannelMessageHandler; use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; use util::ser::VecWriter; -use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; use ln::wire; use ln::wire::Encode; use util::byte_utils; @@ -29,6 +28,9 @@ use std::ops::Deref; use bitcoin_hashes::sha256::Hash as Sha256; use bitcoin_hashes::sha256::HashEngine as Sha256Engine; use bitcoin_hashes::{HashEngine, Hash}; +use ln::peers::handshake::PeerHandshake; +use ln::peers::conduit::Conduit; +use ln::peers::handshake::acts::Act; /// Provides references to trait impls which handle different types of messages. pub struct MessageHandler where CM::Target: msgs::ChannelMessageHandler { @@ -105,8 +107,23 @@ enum InitSyncTracker{ NodesSyncing(PublicKey), } +enum PeerState { + Handshake(PeerHandshake), + Connected(Conduit), +} + +impl PeerState { + fn is_ready_for_encryption(&self) -> bool { + if let PeerState::Connected(_) = self { + true + } else { + false + } + } +} + struct Peer { - channel_encryptor: PeerChannelEncryptor, + encryptor: PeerState, outbound: bool, their_node_id: Option, their_features: Option, @@ -116,8 +133,6 @@ struct Peer { awaiting_write_event: bool, pending_read_buffer: Vec, - pending_read_buffer_pos: usize, - pending_read_is_header: bool, sync_status: InitSyncTracker, @@ -233,7 +248,7 @@ impl PeerManager where pub fn get_peer_node_ids(&self) -> Vec { let peers = self.peers.lock().unwrap(); peers.peers.values().filter_map(|p| { - if !p.channel_encryptor.is_ready_for_encryption() || p.their_features.is_none() { + if !p.encryptor.is_ready_for_encryption() || p.their_features.is_none() { return None; } p.their_node_id @@ -262,13 +277,13 @@ impl PeerManager where /// Panics if descriptor is duplicative with some other descriptor which has not yet has a /// disconnect_event. pub fn new_outbound_connection(&self, their_node_id: PublicKey, descriptor: Descriptor) -> Result, PeerHandleError> { - let mut peer_encryptor = PeerChannelEncryptor::new_outbound(their_node_id.clone(), self.get_ephemeral_key()); - let res = peer_encryptor.get_act_one().to_vec(); - let pending_read_buffer = [0; 50].to_vec(); // Noise act two is 50 bytes + let mut handshake = PeerHandshake::new(&self.our_node_secret, None); + let act_one = handshake.initiate(&self.get_ephemeral_key(), &their_node_id).unwrap(); + let res = Act::One(act_one).serialize(); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { - channel_encryptor: peer_encryptor, + encryptor: PeerState::Handshake(handshake), outbound: true, their_node_id: None, their_features: None, @@ -277,9 +292,7 @@ impl PeerManager where pending_outbound_buffer_first_msg_offset: 0, awaiting_write_event: false, - pending_read_buffer: pending_read_buffer, - pending_read_buffer_pos: 0, - pending_read_is_header: false, + pending_read_buffer: Vec::new(), sync_status: InitSyncTracker::NoSyncRequested, @@ -300,12 +313,11 @@ impl PeerManager where /// Panics if descriptor is duplicative with some other descriptor which has not yet has a /// disconnect_event. pub fn new_inbound_connection(&self, descriptor: Descriptor) -> Result<(), PeerHandleError> { - let peer_encryptor = PeerChannelEncryptor::new_inbound(&self.our_node_secret); - let pending_read_buffer = [0; 50].to_vec(); // Noise act one is 50 bytes + let handshake = PeerHandshake::new(&self.our_node_secret, None); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { - channel_encryptor: peer_encryptor, + encryptor: PeerState::Handshake(handshake), outbound: false, their_node_id: None, their_features: None, @@ -314,9 +326,7 @@ impl PeerManager where pending_outbound_buffer_first_msg_offset: 0, awaiting_write_event: false, - pending_read_buffer: pending_read_buffer, - pending_read_buffer_pos: 0, - pending_read_is_header: false, + pending_read_buffer: Vec::new(), sync_status: InitSyncTracker::NoSyncRequested, @@ -332,7 +342,9 @@ impl PeerManager where ($msg: expr) => { { log_trace!(self, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!($msg)[..])); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!($msg)[..])); + } } } } @@ -450,317 +462,277 @@ impl PeerManager where let pause_read = match peers.peers.get_mut(peer_descriptor) { None => panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => { - assert!(peer.pending_read_buffer.len() > 0); - assert!(peer.pending_read_buffer.len() > peer.pending_read_buffer_pos); + peer.pending_read_buffer.extend_from_slice(&data); + while peer.pending_read_buffer.len() > 0 { + + macro_rules! encode_and_send_msg { + ($msg: expr) => { + { + log_trace!(self, "Encoding and sending message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(&$msg)[..])); + } + peers.peers_needing_send.insert(peer_descriptor.clone()); + } + } + } - let mut read_pos = 0; - while read_pos < data.len() { - { - let data_to_copy = cmp::min(peer.pending_read_buffer.len() - peer.pending_read_buffer_pos, data.len() - read_pos); - peer.pending_read_buffer[peer.pending_read_buffer_pos..peer.pending_read_buffer_pos + data_to_copy].copy_from_slice(&data[read_pos..read_pos + data_to_copy]); - read_pos += data_to_copy; - peer.pending_read_buffer_pos += data_to_copy; + macro_rules! try_potential_handleerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(e) => { + match e.action { + msgs::ErrorAction::DisconnectPeer { msg: _ } => { + //TODO: Try to push msg + log_trace!(self, "Got Err handling message, disconnecting peer because {}", e.err); + return Err(PeerHandleError{ no_connection_possible: false }); + }, + msgs::ErrorAction::IgnoreError => { + log_trace!(self, "Got Err handling message, ignoring because {}", e.err); + continue; + }, + msgs::ErrorAction::SendErrorMessage { msg } => { + log_trace!(self, "Got Err handling message, sending Error message because {}", e.err); + encode_and_send_msg!(msg); + continue; + }, + } + } + }; + } + } + + macro_rules! insert_node_id { + () => { + match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { + hash_map::Entry::Occupied(_) => { + log_trace!(self, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); + peer.their_node_id = None; // Unset so that we don't generate a peer_disconnected event + return Err(PeerHandleError{ no_connection_possible: false }) + }, + hash_map::Entry::Vacant(entry) => { + log_trace!(self, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); + entry.insert(peer_descriptor.clone()) + }, + }; + } } - if peer.pending_read_buffer_pos == peer.pending_read_buffer.len() { - peer.pending_read_buffer_pos = 0; + if let PeerState::Handshake(ref mut handshake) = &mut peer.encryptor { + let (response, conduit, remote_pubkey) = handshake.process_act(&peer.pending_read_buffer, None).unwrap(); + peer.pending_read_buffer.drain(..); // we read it all - macro_rules! encode_and_send_msg { - ($msg: expr) => { - { - log_trace!(self, "Encoding and sending message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(&$msg)[..])); - peers.peers_needing_send.insert(peer_descriptor.clone()); - } - } + peer.pending_outbound_buffer.push_back(response); + if let Some(conduit) = conduit { + peer.encryptor = PeerState::Connected(conduit); } + } - macro_rules! try_potential_handleerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(e) => { - match e.action { - msgs::ErrorAction::DisconnectPeer { msg: _ } => { - //TODO: Try to push msg - log_trace!(self, "Got Err handling message, disconnecting peer because {}", e.err); - return Err(PeerHandleError{ no_connection_possible: false }); - }, - msgs::ErrorAction::IgnoreError => { - log_trace!(self, "Got Err handling message, ignoring because {}", e.err); - continue; - }, - msgs::ErrorAction::SendErrorMessage { msg } => { - log_trace!(self, "Got Err handling message, sending Error message because {}", e.err); - encode_and_send_msg!(msg); - continue; - }, - } - } - }; - } + if let PeerState::Connected(ref mut conduit) = &mut peer.encryptor { + let mut messages = conduit.decrypt_message_stream(Some(&peer.pending_read_buffer)); + + if messages.len() != 1 { + break; // the length should initially be one, though there will be a possibility of decrypting multiple messages at once in the future } - macro_rules! insert_node_id { - () => { - match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { - hash_map::Entry::Occupied(_) => { - log_trace!(self, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); - peer.their_node_id = None; // Unset so that we don't generate a peer_disconnected event - return Err(PeerHandleError{ no_connection_possible: false }) - }, - hash_map::Entry::Vacant(entry) => { - log_trace!(self, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); - entry.insert(peer_descriptor.clone()) - }, - }; + let msg_data = messages.remove(1); + + let mut reader = ::std::io::Cursor::new(&msg_data[..]); + let message_result = wire::read(&mut reader); + let message = match message_result { + Ok(x) => x, + Err(e) => { + match e { + msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::UnknownRequiredFeature => { + log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + continue; + } + msgs::DecodeError::InvalidValue => { + log_debug!(self, "Got an invalid value while deserializing message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ShortRead => { + log_debug!(self, "Deserialization failed due to shortness of message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ExtraAddressesPerType => { + log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407"); + continue; + } + msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), + } } + }; + + log_trace!(self, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + + // Need an Init as first message + if let wire::Message::Init(_) = message { + } else if peer.their_features.is_none() { + log_trace!(self, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); + return Err(PeerHandleError{ no_connection_possible: false }); } - let next_step = peer.channel_encryptor.get_noise_step(); - match next_step { - NextNoiseStep::ActOne => { - let act_two = try_potential_handleerror!(peer.channel_encryptor.process_act_one_with_keys(&peer.pending_read_buffer[..], &self.our_node_secret, self.get_ephemeral_key())).to_vec(); - peer.pending_outbound_buffer.push_back(act_two); - peer.pending_read_buffer = [0; 66].to_vec(); // act three is 66 bytes long - }, - NextNoiseStep::ActTwo => { - let (act_three, their_node_id) = try_potential_handleerror!(peer.channel_encryptor.process_act_two(&peer.pending_read_buffer[..], &self.our_node_secret)); - peer.pending_outbound_buffer.push_back(act_three.to_vec()); - peer.pending_read_buffer = [0; 18].to_vec(); // Message length header is 18 bytes - peer.pending_read_is_header = true; - - peer.their_node_id = Some(their_node_id); - insert_node_id!(); - let mut features = InitFeatures::supported(); - if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.set_initial_routing_sync(); + match message { + // Setup and Control messages: + wire::Message::Init(msg) => { + if msg.features.requires_unknown_bits() { + log_info!(self, "Peer global features required unknown version bits"); + return Err(PeerHandleError{ no_connection_possible: true }); + } + if msg.features.requires_unknown_bits() { + log_info!(self, "Peer local features required unknown version bits"); + return Err(PeerHandleError{ no_connection_possible: true }); + } + if peer.their_features.is_some() { + return Err(PeerHandleError{ no_connection_possible: false }); } - let resp = msgs::Init { features }; - encode_and_send_msg!(resp); - }, - NextNoiseStep::ActThree => { - let their_node_id = try_potential_handleerror!(peer.channel_encryptor.process_act_three(&peer.pending_read_buffer[..])); - peer.pending_read_buffer = [0; 18].to_vec(); // Message length header is 18 bytes - peer.pending_read_is_header = true; - peer.their_node_id = Some(their_node_id); - insert_node_id!(); - }, - NextNoiseStep::NoiseComplete => { - if peer.pending_read_is_header { - let msg_len = try_potential_handleerror!(peer.channel_encryptor.decrypt_length_header(&peer.pending_read_buffer[..])); - peer.pending_read_buffer = Vec::with_capacity(msg_len as usize + 16); - peer.pending_read_buffer.resize(msg_len as usize + 16, 0); - if msg_len < 2 { // Need at least the message type tag - return Err(PeerHandleError{ no_connection_possible: false }); - } - peer.pending_read_is_header = false; - } else { - let msg_data = try_potential_handleerror!(peer.channel_encryptor.decrypt_message(&peer.pending_read_buffer[..])); - assert!(msg_data.len() >= 2); - - // Reset read buffer - peer.pending_read_buffer = [0; 18].to_vec(); - peer.pending_read_is_header = true; - - let mut reader = ::std::io::Cursor::new(&msg_data[..]); - let message_result = wire::read(&mut reader); - let message = match message_result { - Ok(x) => x, - Err(e) => { - match e { - msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to update!"); - continue; - } - msgs::DecodeError::InvalidValue => { - log_debug!(self, "Got an invalid value while deserializing message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ShortRead => { - log_debug!(self, "Deserialization failed due to shortness of message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ExtraAddressesPerType => { - log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407"); - continue; - } - msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), - } - } - }; + log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", + if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, + if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, + if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, + if msg.features.supports_unknown_bits() { "present" } else { "none" }, + if msg.features.supports_unknown_bits() { "present" } else { "none" }); - log_trace!(self, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + if msg.features.initial_routing_sync() { + peer.sync_status = InitSyncTracker::ChannelsSyncing(0); + peers.peers_needing_send.insert(peer_descriptor.clone()); + } - // Need an Init as first message - if let wire::Message::Init(_) = message { - } else if peer.their_features.is_none() { - log_trace!(self, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); - return Err(PeerHandleError{ no_connection_possible: false }); + if !peer.outbound { + let mut features = InitFeatures::supported(); + if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.set_initial_routing_sync(); } - match message { - // Setup and Control messages: - wire::Message::Init(msg) => { - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer global features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }); - } - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer local features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }); - } - if peer.their_features.is_some() { - return Err(PeerHandleError{ no_connection_possible: false }); - } - - log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", - if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, - if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, - if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, - if msg.features.supports_unknown_bits() { "present" } else { "none" }, - if msg.features.supports_unknown_bits() { "present" } else { "none" }); - - if msg.features.initial_routing_sync() { - peer.sync_status = InitSyncTracker::ChannelsSyncing(0); - peers.peers_needing_send.insert(peer_descriptor.clone()); - } - - if !peer.outbound { - let mut features = InitFeatures::supported(); - if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.set_initial_routing_sync(); - } - - let resp = msgs::Init { features }; - encode_and_send_msg!(resp); - } - - self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); - peer.their_features = Some(msg.features); - }, - wire::Message::Error(msg) => { - let mut data_is_printable = true; - for b in msg.data.bytes() { - if b < 32 || b > 126 { - data_is_printable = false; - break; - } - } - - if data_is_printable { - log_debug!(self, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); - } else { - log_debug!(self, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); - } - self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); - if msg.channel_id == [0; 32] { - return Err(PeerHandleError{ no_connection_possible: true }); - } - }, + let resp = msgs::Init { features }; + encode_and_send_msg!(resp); + } - wire::Message::Ping(msg) => { - if msg.ponglen < 65532 { - let resp = msgs::Pong { byteslen: msg.ponglen }; - encode_and_send_msg!(resp); - } - }, - wire::Message::Pong(_msg) => { - peer.awaiting_pong = false; - }, + self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); + peer.their_features = Some(msg.features); + }, + wire::Message::Error(msg) => { + let mut data_is_printable = true; + for b in msg.data.bytes() { + if b < 32 || b > 126 { + data_is_printable = false; + break; + } + } - // Channel messages: - wire::Message::OpenChannel(msg) => { - self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - }, - wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - }, + if data_is_printable { + log_debug!(self, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); + } else { + log_debug!(self, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); + } + self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); + if msg.channel_id == [0; 32] { + return Err(PeerHandleError{ no_connection_possible: true }); + } + }, - wire::Message::FundingCreated(msg) => { - self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::FundingSigned(msg) => { - self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::FundingLocked(msg) => { - self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); - }, + wire::Message::Ping(msg) => { + if msg.ponglen < 65532 { + let resp = msgs::Pong { byteslen: msg.ponglen }; + encode_and_send_msg!(resp); + } + }, + wire::Message::Pong(_msg) => { + peer.awaiting_pong = false; + }, - wire::Message::Shutdown(msg) => { - self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::ClosingSigned(msg) => { - self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); - }, + // Channel messages: + wire::Message::OpenChannel(msg) => { + self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + }, + wire::Message::AcceptChannel(msg) => { + self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + }, - // Commitment messages: - wire::Message::UpdateAddHTLC(msg) => { - self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFulfillHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFailHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFailMalformedHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); - }, + wire::Message::FundingCreated(msg) => { + self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::FundingSigned(msg) => { + self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::FundingLocked(msg) => { + self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); + }, - wire::Message::CommitmentSigned(msg) => { - self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::RevokeAndACK(msg) => { - self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFee(msg) => { - self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::ChannelReestablish(msg) => { - self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); - }, + wire::Message::Shutdown(msg) => { + self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::ClosingSigned(msg) => { + self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); + }, - // Routing messages: - wire::Message::AnnouncementSignatures(msg) => { - self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::ChannelAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); + // Commitment messages: + wire::Message::UpdateAddHTLC(msg) => { + self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFulfillHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFailHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFailMalformedHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); + }, - if should_forward { - // TODO: forward msg along to all our other peers! - } - }, - wire::Message::NodeAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); + wire::Message::CommitmentSigned(msg) => { + self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::RevokeAndACK(msg) => { + self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFee(msg) => { + self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::ChannelReestablish(msg) => { + self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); + }, - if should_forward { - // TODO: forward msg along to all our other peers! - } - }, - wire::Message::ChannelUpdate(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); + // Routing messages: + wire::Message::AnnouncementSignatures(msg) => { + self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::ChannelAnnouncement(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); - if should_forward { - // TODO: forward msg along to all our other peers! - } - }, + if should_forward { + // TODO: forward msg along to all our other peers! + } + }, + wire::Message::NodeAnnouncement(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); - // Unknown messages: - wire::Message::Unknown(msg_type) if msg_type.is_even() => { - // Fail the channel if message is an even, unknown type as per BOLT #1. - return Err(PeerHandleError{ no_connection_possible: true }); - }, - wire::Message::Unknown(_) => {}, - } + if should_forward { + // TODO: forward msg along to all our other peers! } - } + }, + wire::Message::ChannelUpdate(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); + + if should_forward { + // TODO: forward msg along to all our other peers! + } + }, + + // Unknown messages: + wire::Message::Unknown(msg_type) if msg_type.is_even() => { + // Fail the channel if message is an even, unknown type as per BOLT #1. + return Err(PeerHandleError{ no_connection_possible: true }); + }, + wire::Message::Unknown(_) => {}, } } + } self.do_attempt_write_data(peer_descriptor, peer); @@ -819,7 +791,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Drop the pending channel? (or just let it timeout, but that sucks) }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendOpenChannel { ref node_id, ref msg } => { @@ -829,7 +803,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Drop the pending channel? (or just let it timeout, but that sucks) }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendFundingCreated { ref node_id, ref msg } => { @@ -841,7 +817,9 @@ impl PeerManager where //TODO: generate a DiscardFunding event indicating to the wallet that //they should just throw away this funding transaction }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendFundingSigned { ref node_id, ref msg } => { @@ -852,7 +830,9 @@ impl PeerManager where //TODO: generate a DiscardFunding event indicating to the wallet that //they should just throw away this funding transaction }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendFundingLocked { ref node_id, ref msg } => { @@ -862,7 +842,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Do whatever we're gonna do for handling dropped messages }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } => { @@ -873,7 +855,9 @@ impl PeerManager where //TODO: generate a DiscardFunding event indicating to the wallet that //they should just throw away this funding transaction }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { @@ -887,21 +871,33 @@ impl PeerManager where //TODO: Do whatever we're gonna do for handling dropped messages }); for msg in update_add_htlcs { - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } } for msg in update_fulfill_htlcs { - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } } for msg in update_fail_htlcs { - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } } for msg in update_fail_malformed_htlcs { - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } } if let &Some(ref msg) = update_fee { - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } + } + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(commitment_signed))); } - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(commitment_signed))); self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => { @@ -911,7 +907,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Do whatever we're gonna do for handling dropped messages }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendClosingSigned { ref node_id, ref msg } => { @@ -921,7 +919,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Do whatever we're gonna do for handling dropped messages }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendShutdown { ref node_id, ref msg } => { @@ -931,7 +931,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Do whatever we're gonna do for handling dropped messages }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => { @@ -941,7 +943,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Do whatever we're gonna do for handling dropped messages }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, MessageSendEvent::BroadcastChannelAnnouncement { ref msg, ref update_msg } => { @@ -951,8 +955,8 @@ impl PeerManager where let encoded_update_msg = encode_msg!(update_msg); for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.channel_encryptor.is_ready_for_encryption() || peer.their_features.is_none() || - !peer.should_forward_channel(msg.contents.short_channel_id) { + if !peer.encryptor.is_ready_for_encryption() || peer.their_features.is_none() || + !peer.should_forward_channel(msg.contents.short_channel_id) { continue } match peer.their_node_id { @@ -963,8 +967,10 @@ impl PeerManager where } } } - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_msg[..])); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_update_msg[..])); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_msg[..])); + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_update_msg[..])); + } self.do_attempt_write_data(&mut (*descriptor).clone(), peer); } } @@ -975,11 +981,13 @@ impl PeerManager where let encoded_msg = encode_msg!(msg); for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.channel_encryptor.is_ready_for_encryption() || peer.their_features.is_none() || - !peer.should_forward_channel(msg.contents.short_channel_id) { + if !peer.encryptor.is_ready_for_encryption() || peer.their_features.is_none() || + !peer.should_forward_channel(msg.contents.short_channel_id) { continue } - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_msg[..])); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_msg[..])); + } self.do_attempt_write_data(&mut (*descriptor).clone(), peer); } } @@ -997,7 +1005,9 @@ impl PeerManager where log_trace!(self, "Handling DisconnectPeer HandleError event in peer_handler for node {} with message {}", log_pubkey!(node_id), msg.data); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } // This isn't guaranteed to work, but if there is enough free // room in the send buffer, put the error message there... self.do_attempt_write_data(&mut descriptor, &mut peer); @@ -1017,7 +1027,9 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Do whatever we're gonna do for handling dropped messages }); - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(msg))); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); + } self.do_attempt_write_data(&mut descriptor, peer); }, } diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 087f7ecfa73..0bbd8aa189e 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -9,7 +9,7 @@ use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo}; use ln::peers::handshake::hash::HandshakeHash; use ln::peers::handshake::states::{ActOneExpectation, ActThreeExpectation, ActTwoExpectation, HandshakeState}; -mod acts; +pub(crate) mod acts; mod hash; mod states; mod tests; From 92eac9b6c9359aa34b02fd9b94140fc43925428c Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 12 Feb 2020 11:48:11 -0800 Subject: [PATCH 03/96] make ephemeral private key explicit for handshake (todo: remove it from the state machine) --- lightning/src/ln/peer_handler.rs | 6 +-- lightning/src/ln/peers/conduit.rs | 10 +---- lightning/src/ln/peers/handshake/mod.rs | 46 +++++++---------------- lightning/src/ln/peers/handshake/tests.rs | 8 ++-- 4 files changed, 21 insertions(+), 49 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 44f0214b0fc..09e1d5b7657 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -277,8 +277,8 @@ impl PeerManager where /// Panics if descriptor is duplicative with some other descriptor which has not yet has a /// disconnect_event. pub fn new_outbound_connection(&self, their_node_id: PublicKey, descriptor: Descriptor) -> Result, PeerHandleError> { - let mut handshake = PeerHandshake::new(&self.our_node_secret, None); - let act_one = handshake.initiate(&self.get_ephemeral_key(), &their_node_id).unwrap(); + let mut handshake = PeerHandshake::new(&self.our_node_secret, &self.get_ephemeral_key()); + let act_one = handshake.initiate(&their_node_id).unwrap(); let res = Act::One(act_one).serialize(); let mut peers = self.peers.lock().unwrap(); @@ -313,7 +313,7 @@ impl PeerManager where /// Panics if descriptor is duplicative with some other descriptor which has not yet has a /// disconnect_event. pub fn new_inbound_connection(&self, descriptor: Descriptor) -> Result<(), PeerHandleError> { - let handshake = PeerHandshake::new(&self.our_node_secret, None); + let handshake = PeerHandshake::new(&self.our_node_secret, &self.get_ephemeral_key()); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index fe1c5adcb90..28c83f3c772 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -31,14 +31,8 @@ impl Conduit { } pub(super) fn read(&mut self, data: &[u8]) { - let mut read_buffer = if let Some(buffer) = self.read_buffer.take() { - buffer - } else { - Vec::new() - }; - + let mut read_buffer = self.read_buffer.get_or_insert(Vec::new()); read_buffer.extend_from_slice(data); - self.read_buffer = Some(read_buffer); } /// Add newly received data from the peer node to the buffer and decrypt all possible messages @@ -71,8 +65,6 @@ impl Conduit { } } - self.read_buffer = Some(read_buffer); - messages } diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 0bbd8aa189e..70d2082269f 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -17,24 +17,18 @@ mod tests; pub struct PeerHandshake { state: Option, private_key: SecretKey, + ephemeral_private_key: SecretKey, - preset_ephemeral_private_key: Option, read_buffer: Vec, } impl PeerHandshake { - pub fn new(private_key: &SecretKey, ephemeral_private_key: Option<&SecretKey>) -> Self { - let preset_ephemeral_private_key = if let Some(key) = ephemeral_private_key { - // deref and clone - Some((*key).clone()) - } else { - None - }; + pub fn new(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { let handshake = PeerHandshake { state: Some(HandshakeState::Blank), private_key: (*private_key).clone(), - preset_ephemeral_private_key, + ephemeral_private_key: (*ephemeral_private_key).clone(), read_buffer: Vec::new(), }; handshake @@ -80,9 +74,7 @@ impl PeerHandshake { match &self.state { Some(HandshakeState::Blank) => { let remote_public_key = remote_public_key.ok_or("Call make_initiator() first")?; - let ephemeral_private_key = self.obtain_ephemeral_private_key(); - - let act_one = self.initiate(&ephemeral_private_key, &remote_public_key)?; + let act_one = self.initiate(&remote_public_key)?; response = act_one.0.to_vec(); } Some(HandshakeState::AwaitingActOne(_)) => { @@ -95,9 +87,7 @@ impl PeerHandshake { act_one_buffer.copy_from_slice(&self.read_buffer[..act_length]); self.read_buffer.drain(..act_length); - let ephemeral_private_key = self.obtain_ephemeral_private_key(); - - let act_two = self.process_act_one(ActOne(act_one_buffer), &ephemeral_private_key)?; + let act_two = self.process_act_one(ActOne(act_one_buffer))?; response = act_two.0.to_vec(); } Some(HandshakeState::AwaitingActTwo(_)) => { @@ -147,7 +137,7 @@ impl PeerHandshake { Ok((response, connected_peer, remote_pubkey)) } - pub fn initiate(&mut self, ephemeral_private_key: &SecretKey, remote_public_key: &PublicKey) -> Result { + pub fn initiate(&mut self, remote_public_key: &PublicKey) -> Result { if let Some(HandshakeState::Blank) = &self.state {} else { return Err("incorrect state".to_string()); } @@ -156,7 +146,7 @@ impl PeerHandshake { // serialize act one let (act_one, chaining_key, temporary_key) = self.calculate_act_message( - ephemeral_private_key, + &self.ephemeral_private_key, remote_public_key, chaining_key, &mut hash, @@ -166,13 +156,13 @@ impl PeerHandshake { hash, chaining_key, temporary_key, - ephemeral_private_key: (*ephemeral_private_key).clone(), + ephemeral_private_key: (*&self.ephemeral_private_key).clone(), })); Ok(ActOne(act_one)) } - pub(crate) fn process_act_one(&mut self, act: ActOne, ephemeral_private_key: &SecretKey) -> Result { + pub(crate) fn process_act_one(&mut self, act: ActOne) -> Result { let state = self.state.take(); let act_one_expectation = match state { Some(HandshakeState::AwaitingActOne(act_state)) => act_state, @@ -200,8 +190,10 @@ impl PeerHandshake { &mut hash, )?; + let ephemeral_private_key = (*&self.ephemeral_private_key).clone(); + let (act_two, chaining_key, temporary_key) = self.calculate_act_message( - ephemeral_private_key, + &ephemeral_private_key, &remote_ephemeral_public_key, chaining_key, &mut hash, @@ -211,7 +203,7 @@ impl PeerHandshake { hash, chaining_key, temporary_key, - ephemeral_private_key: (*ephemeral_private_key).clone(), + ephemeral_private_key, remote_ephemeral_public_key, })); @@ -315,18 +307,6 @@ impl PeerHandshake { Ok((remote_pubkey, connected_peer)) } - fn obtain_ephemeral_private_key(&mut self) -> SecretKey { - if let Some(key) = self.preset_ephemeral_private_key.take() { - key - } else { - // generate a random ephemeral private key right here - let mut rng = thread_rng(); - let mut ephemeral_bytes = [0; 32]; - rng.fill_bytes(&mut ephemeral_bytes); - SecretKey::from_slice(&ephemeral_bytes).expect("You broke elliptic curve cryptography") - } - } - fn calculate_act_message(&self, local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], [u8; 32], [u8; 32]) { let local_public_key = Self::private_key_to_public_key(local_private_key); diff --git a/lightning/src/ln/peers/handshake/tests.rs b/lightning/src/ln/peers/handshake/tests.rs index 48d89a9fde6..b749f9ab13c 100644 --- a/lightning/src/ln/peers/handshake/tests.rs +++ b/lightning/src/ln/peers/handshake/tests.rs @@ -14,13 +14,13 @@ fn test_exchange() { let local_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); let remote_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - let mut local_handshake = PeerHandshake::new(&local_private_key, Some(&local_ephemeral_private_key)); - let mut remote_handshake = PeerHandshake::new(&remote_private_key, Some(&remote_ephemeral_private_key)); + let mut local_handshake = PeerHandshake::new(&local_private_key, &local_ephemeral_private_key); + let mut remote_handshake = PeerHandshake::new(&remote_private_key, &remote_ephemeral_private_key); let remote_public_key = PublicKey::from_secret_key(&curve, &remote_private_key); - let act_1_message = local_handshake.initiate(&local_ephemeral_private_key, &remote_public_key); - let act_2_message = remote_handshake.process_act_one(act_1_message.unwrap(), &remote_ephemeral_private_key); + let act_1_message = local_handshake.initiate(&remote_public_key); + let act_2_message = remote_handshake.process_act_one(act_1_message.unwrap()); let act_3_message = local_handshake.process_act_two(act_2_message.unwrap()); remote_handshake.process_act_three(act_3_message.unwrap().0).unwrap(); } \ No newline at end of file From 986f25f5b7e7fb5ed1743f8112d068732bfaf1bb Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 12 Feb 2020 12:11:00 -0800 Subject: [PATCH 04/96] remove import of rand --- lightning/src/ln/peers/handshake/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 70d2082269f..213ed2bbfa0 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -1,6 +1,5 @@ use bitcoin_hashes::{Hash, HashEngine}; use bitcoin_hashes::sha256::Hash as Sha256; -use rand::{Rng, thread_rng}; use secp256k1::{PublicKey, SecretKey}; use ln::peers::{chacha, hkdf}; From ffbf5ec5d3501e26a77a109dc0155ab9d4f84bba Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 12 Feb 2020 12:28:38 -0800 Subject: [PATCH 05/96] make linter complain less about docs fix last lint doc issue? make the &Some matches explicit for Rust 1.22 appease Rust 1.22 some more with ampersandery appease Rust 1.22 by using byte_utils for endianness functionality appease Rust 1.22 by using byte_utils and ref in match arms experimenting some more with ref matching for Rust 1.22 might Rust 1.22 finally work? Rearranged a lot of borrowing locations and macro behavior and definition locations fix bug that was kindly caught by fuzz tests fix fuzz test improve error messaging the different rust versions are a balancing act, and I can't juggle --- lightning/src/ln/peer_handler.rs | 130 +++++++++++----------- lightning/src/ln/peers/chacha.rs | 13 ++- lightning/src/ln/peers/conduit.rs | 33 +++++- lightning/src/ln/peers/handshake/acts.rs | 11 +- lightning/src/ln/peers/handshake/mod.rs | 27 +++-- lightning/src/ln/peers/handshake/tests.rs | 21 +++- lightning/src/ln/peers/mod.rs | 5 + 7 files changed, 156 insertions(+), 84 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 09e1d5b7657..0aebdf1dc4e 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -114,7 +114,7 @@ enum PeerState { impl PeerState { fn is_ready_for_encryption(&self) -> bool { - if let PeerState::Connected(_) = self { + if let &PeerState::Connected(_) = self { true } else { false @@ -285,7 +285,7 @@ impl PeerManager where if peers.peers.insert(descriptor, Peer { encryptor: PeerState::Handshake(handshake), outbound: true, - their_node_id: None, + their_node_id: Some(their_node_id.clone()), their_features: None, pending_outbound_buffer: LinkedList::new(), @@ -313,7 +313,8 @@ impl PeerManager where /// Panics if descriptor is duplicative with some other descriptor which has not yet has a /// disconnect_event. pub fn new_inbound_connection(&self, descriptor: Descriptor) -> Result<(), PeerHandleError> { - let handshake = PeerHandshake::new(&self.our_node_secret, &self.get_ephemeral_key()); + let mut handshake = PeerHandshake::new(&self.our_node_secret, &self.get_ephemeral_key()); + handshake.make_inbound(); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { @@ -465,78 +466,83 @@ impl PeerManager where peer.pending_read_buffer.extend_from_slice(&data); while peer.pending_read_buffer.len() > 0 { - macro_rules! encode_and_send_msg { - ($msg: expr) => { - { - log_trace!(self, "Encoding and sending message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - if let PeerState::Connected(ref mut conduit) = peer.encryptor { - peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(&$msg)[..])); - } - peers.peers_needing_send.insert(peer_descriptor.clone()); - } + let mut conduit_option = None; + let mut remote_pubkey_option = None; + + if let &mut PeerState::Handshake(ref mut handshake) = &mut peer.encryptor { + let (response, conduit, remote_pubkey) = handshake.process_act(&peer.pending_read_buffer, None).unwrap(); + peer.pending_read_buffer.drain(..); // we read it all + + if let Some(key) = remote_pubkey { + remote_pubkey_option = Some(key); } - } - macro_rules! try_potential_handleerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(e) => { - match e.action { - msgs::ErrorAction::DisconnectPeer { msg: _ } => { - //TODO: Try to push msg - log_trace!(self, "Got Err handling message, disconnecting peer because {}", e.err); - return Err(PeerHandleError{ no_connection_possible: false }); - }, - msgs::ErrorAction::IgnoreError => { - log_trace!(self, "Got Err handling message, ignoring because {}", e.err); - continue; - }, - msgs::ErrorAction::SendErrorMessage { msg } => { - log_trace!(self, "Got Err handling message, sending Error message because {}", e.err); - encode_and_send_msg!(msg); - continue; - }, - } - } - }; + peer.pending_outbound_buffer.push_back(response); + if let Some(conduit) = conduit { + conduit_option = Some(conduit); } } - macro_rules! insert_node_id { - () => { - match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { - hash_map::Entry::Occupied(_) => { - log_trace!(self, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); - peer.their_node_id = None; // Unset so that we don't generate a peer_disconnected event - return Err(PeerHandleError{ no_connection_possible: false }) - }, - hash_map::Entry::Vacant(entry) => { - log_trace!(self, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); - entry.insert(peer_descriptor.clone()) - }, - }; - } + if let Some(key) = remote_pubkey_option { + peer.their_node_id = Some(key); } - if let PeerState::Handshake(ref mut handshake) = &mut peer.encryptor { - let (response, conduit, remote_pubkey) = handshake.process_act(&peer.pending_read_buffer, None).unwrap(); - peer.pending_read_buffer.drain(..); // we read it all + if let Some(conduit) = conduit_option { + // Rust 1.22 does not allow assignment in a borrowed context, even if mutable + peer.encryptor = PeerState::Connected(conduit); + } - peer.pending_outbound_buffer.push_back(response); - if let Some(conduit) = conduit { - peer.encryptor = PeerState::Connected(conduit); + if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { + + macro_rules! encode_and_send_msg { + ($msg: expr) => { + { + log_trace!(self, "Encoding and sending message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + // we are in a context where conduit is known + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(&$msg)[..])); + peers.peers_needing_send.insert(peer_descriptor.clone()); + } + } + } + + macro_rules! try_potential_handleerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(e) => { + match e.action { + msgs::ErrorAction::DisconnectPeer { msg: _ } => { + //TODO: Try to push msg + log_trace!(self, "Got Err handling message, disconnecting peer because {}", e.err); + return Err(PeerHandleError{ no_connection_possible: false }); + }, + msgs::ErrorAction::IgnoreError => { + log_trace!(self, "Got Err handling message, ignoring because {}", e.err); + continue; + }, + msgs::ErrorAction::SendErrorMessage { msg } => { + log_trace!(self, "Got Err handling message, sending Error message because {}", e.err); + encode_and_send_msg!(msg); + continue; + }, + } + } + }; + } } - } - if let PeerState::Connected(ref mut conduit) = &mut peer.encryptor { - let mut messages = conduit.decrypt_message_stream(Some(&peer.pending_read_buffer)); + let mut next_message_result = conduit.decrypt(&peer.pending_read_buffer); - if messages.len() != 1 { - break; // the length should initially be one, though there will be a possibility of decrypting multiple messages at once in the future + let offset = next_message_result.1; + if offset == 0 { + // nothing got read + break; + }else{ + peer.pending_read_buffer.drain(0..offset); } - let msg_data = messages.remove(1); + // something got read, so we definitely have a message + let msg_data = next_message_result.0.unwrap(); let mut reader = ::std::io::Cursor::new(&msg_data[..]); let message_result = wire::read(&mut reader); diff --git a/lightning/src/ln/peers/chacha.rs b/lightning/src/ln/peers/chacha.rs index 4b29b924388..e82e55a91c6 100644 --- a/lightning/src/ln/peers/chacha.rs +++ b/lightning/src/ln/peers/chacha.rs @@ -1,8 +1,9 @@ +use util::byte_utils; use util::chacha20poly1305rfc::ChaCha20Poly1305RFC; pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) -> Vec { let mut nonce_bytes = [0; 12]; - nonce_bytes[4..].copy_from_slice(&nonce.to_le_bytes()); + nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce)); let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data); let mut ciphertext = vec![0u8; plaintext.len()]; @@ -17,11 +18,15 @@ pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext: &[u8]) -> Result, String> { let mut nonce_bytes = [0; 12]; - nonce_bytes[4..].copy_from_slice(&nonce.to_le_bytes()); + nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce)); let length = tagged_ciphertext.len(); - let ciphertext = &tagged_ciphertext[0..length - 16]; - let authentication_tag = &tagged_ciphertext[length - 16..length]; + if length < 16 { + return Err("ciphertext cannot be shorter than tag length of 16 bytes".to_string()); + } + let end_index = length - 16; + let ciphertext = &tagged_ciphertext[0..end_index]; + let authentication_tag = &tagged_ciphertext[end_index..length]; let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data); let mut plaintext = vec![0u8; length - 16]; diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 28c83f3c772..019d3c11d63 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -1,6 +1,11 @@ +//! Handles all over the wire message encryption and decryption upon handshake completion. + use ln::peers::{chacha, hkdf}; +use util::byte_utils; /// Returned after a successful handshake to encrypt and decrypt communication with peer nodes +/// Automatically handles key rotation. +/// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering. pub struct Conduit { pub(crate) sending_key: [u8; 32], pub(crate) receiving_key: [u8; 32], @@ -15,9 +20,10 @@ pub struct Conduit { } impl Conduit { + /// Encrypt data to be sent to peer pub fn encrypt(&mut self, buffer: &[u8]) -> Vec { let length = buffer.len() as u16; - let length_bytes = length.to_be_bytes(); + let length_bytes = byte_utils::be16_to_array(length); let encrypted_length = chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes); self.increment_sending_nonce(); @@ -69,7 +75,7 @@ impl Conduit { } /// Decrypt a single message. Buffer is an undelimited amount of bytes - fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { // the response slice should have the same lifetime as the argument. It's the slice data is read from + pub(crate) fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { // the response slice should have the same lifetime as the argument. It's the slice data is read from if buffer.len() < 18 { return (None, 0); } @@ -78,9 +84,9 @@ impl Conduit { let length_vec = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap(); let mut length_bytes = [0u8; 2]; length_bytes.copy_from_slice(length_vec.as_slice()); - let message_length = u16::from_be_bytes(length_bytes) as usize; + let message_length = byte_utils::slice_to_be16(&length_bytes) as usize; - let message_end_index = message_length + 18; // todo: abort if too short + let message_end_index = message_length + 18 + 16; // todo: abort if too short if buffer.len() < message_end_index { return (None, 0); } @@ -121,6 +127,7 @@ impl Conduit { #[cfg(test)] mod tests { + use hex; use ln::peers::conduit::Conduit; #[test] @@ -147,6 +154,16 @@ mod tests { read_buffer: None, }; + let mut remote_peer = Conduit { + sending_key: receiving_key, + receiving_key: sending_key, + sending_chaining_key: chaining_key, + receiving_chaining_key: chaining_key, + sending_nonce: 0, + receiving_nonce: 0, + read_buffer: None, + }; + let message = hex::decode("68656c6c6f").unwrap(); let mut encrypted_messages: Vec> = Vec::new(); @@ -161,5 +178,13 @@ mod tests { assert_eq!(encrypted_messages[501], hex::decode("1b186c57d44eb6de4c057c49940d79bb838a145cb528d6e8fd26dbe50a60ca2c104b56b60e45bd").unwrap()); assert_eq!(encrypted_messages[1000], hex::decode("4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09").unwrap()); assert_eq!(encrypted_messages[1001], hex::decode("2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36").unwrap()); + + for _ in 0..1002 { + let encrypted_message = encrypted_messages.remove(0); + let mut decrypted_messages = remote_peer.decrypt_message_stream(Some(&encrypted_message)); + assert_eq!(decrypted_messages.len(), 1); + let decrypted_message = decrypted_messages.remove(0); + assert_eq!(decrypted_message, hex::decode("68656c6c6f").unwrap()); + } } } \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs index 1a42e5dd430..93e582908a7 100644 --- a/lightning/src/ln/peers/handshake/acts.rs +++ b/lightning/src/ln/peers/handshake/acts.rs @@ -1,15 +1,19 @@ +/// Wrapper for the first act message pub struct ActOne( pub(super) [u8; 50] ); +/// Wrapper for the second act message pub struct ActTwo( pub(super) [u8; 50] ); +/// Wrapper for the third act message pub struct ActThree( pub(super) [u8; 66] ); +/// Wrapper for any act message pub enum Act { One(ActOne), Two(ActTwo), @@ -17,15 +21,16 @@ pub enum Act { } impl Act { + /// Convert any act into a byte vector pub fn serialize(&self) -> Vec { match self { - Act::One(act) => { + &Act::One(ref act) => { act.0.to_vec() } - Act::Two(act) => { + &Act::Two(ref act) => { act.0.to_vec() } - Act::Three(act) => { + &Act::Three(ref act) => { act.0.to_vec() } } diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 213ed2bbfa0..482b497149e 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -1,3 +1,9 @@ +//! Execute handshakes for peer-to-peer connection establishment. +//! Handshake states can be advanced automatically, or by manually calling the appropriate step. +//! Once complete, returns an instance of Conduit. + +use secp256k1; + use bitcoin_hashes::{Hash, HashEngine}; use bitcoin_hashes::sha256::Hash as Sha256; use secp256k1::{PublicKey, SecretKey}; @@ -13,6 +19,8 @@ mod hash; mod states; mod tests; +/// Object for managing handshakes. +/// Currently requires explicit ephemeral private key specification. pub struct PeerHandshake { state: Option, private_key: SecretKey, @@ -22,8 +30,8 @@ pub struct PeerHandshake { } impl PeerHandshake { + /// Instantiate a new handshake with a node identity secret key and an ephemeral private key pub fn new(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { - let handshake = PeerHandshake { state: Some(HandshakeState::Blank), private_key: (*private_key).clone(), @@ -33,6 +41,7 @@ impl PeerHandshake { handshake } + /// Make the handshake object inbound in anticipation of a peer's first handshake act pub fn make_inbound(&mut self) { let public_key = Self::private_key_to_public_key(&self.private_key); let (hash, chaining_key) = Self::initialize_state(&public_key); @@ -71,12 +80,12 @@ impl PeerHandshake { let read_buffer_length = self.read_buffer.len(); match &self.state { - Some(HandshakeState::Blank) => { - let remote_public_key = remote_public_key.ok_or("Call make_initiator() first")?; + &Some(HandshakeState::Blank) => { + let remote_public_key = remote_public_key.ok_or("remote_public_key must be Some for outbound connections")?; let act_one = self.initiate(&remote_public_key)?; response = act_one.0.to_vec(); } - Some(HandshakeState::AwaitingActOne(_)) => { + &Some(HandshakeState::AwaitingActOne(_)) => { let act_length = 50; if read_buffer_length < act_length { return Err("need at least 50 bytes".to_string()); @@ -89,7 +98,7 @@ impl PeerHandshake { let act_two = self.process_act_one(ActOne(act_one_buffer))?; response = act_two.0.to_vec(); } - Some(HandshakeState::AwaitingActTwo(_)) => { + &Some(HandshakeState::AwaitingActTwo(_)) => { let act_length = 50; if read_buffer_length < act_length { return Err("need at least 50 bytes".to_string()); @@ -109,7 +118,7 @@ impl PeerHandshake { response = act_three.0.to_vec(); connected_peer = Some(conduit); } - Some(HandshakeState::AwaitingActThree(_)) => { + &Some(HandshakeState::AwaitingActThree(_)) => { let act_length = 66; if read_buffer_length < act_length { return Err("need at least 50 bytes".to_string()); @@ -136,8 +145,9 @@ impl PeerHandshake { Ok((response, connected_peer, remote_pubkey)) } + /// Initiate the handshake with a peer and return the first act pub fn initiate(&mut self, remote_public_key: &PublicKey) -> Result { - if let Some(HandshakeState::Blank) = &self.state {} else { + if let &Some(HandshakeState::Blank) = &self.state {} else { return Err("incorrect state".to_string()); } @@ -161,6 +171,7 @@ impl PeerHandshake { Ok(ActOne(act_one)) } + /// Process a peer's incoming first act and return the second act pub(crate) fn process_act_one(&mut self, act: ActOne) -> Result { let state = self.state.take(); let act_one_expectation = match state { @@ -209,6 +220,7 @@ impl PeerHandshake { Ok(ActTwo(act_two)) } + /// Process a peer's incoming second act and return the third act alongside a Conduit instance pub(crate) fn process_act_two(&mut self, act: ActTwo) -> Result<(ActThree, Conduit), String> { let state = self.state.take(); let act_two_expectation = match state { @@ -258,6 +270,7 @@ impl PeerHandshake { Ok((ActThree(act_three), connected_peer)) } + /// Process a peer's incoming third act and return a Conduit instance pub(crate) fn process_act_three(&mut self, act: ActThree) -> Result<(PublicKey, Conduit), String> { let state = self.state.take(); let act_three_expectation = match state { diff --git a/lightning/src/ln/peers/handshake/tests.rs b/lightning/src/ln/peers/handshake/tests.rs index b749f9ab13c..f0dcff6d993 100644 --- a/lightning/src/ln/peers/handshake/tests.rs +++ b/lightning/src/ln/peers/handshake/tests.rs @@ -1,5 +1,8 @@ #![cfg(test)] +use hex; +use secp256k1; + use secp256k1::key::{PublicKey, SecretKey}; use ln::peers::handshake::PeerHandshake; @@ -19,8 +22,18 @@ fn test_exchange() { let remote_public_key = PublicKey::from_secret_key(&curve, &remote_private_key); - let act_1_message = local_handshake.initiate(&remote_public_key); - let act_2_message = remote_handshake.process_act_one(act_1_message.unwrap()); - let act_3_message = local_handshake.process_act_two(act_2_message.unwrap()); - remote_handshake.process_act_three(act_3_message.unwrap().0).unwrap(); + let act_1 = local_handshake.initiate(&remote_public_key).unwrap(); + let act_1_hex = hex::encode(&act_1.0.to_vec()); + assert_eq!(act_1_hex, "00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a"); + + let act_2 = remote_handshake.process_act_one(act_1).unwrap(); + let act_2_hex = hex::encode(&act_2.0.to_vec()); + assert_eq!(act_2_hex, "0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae"); + + let act_2_result = local_handshake.process_act_two(act_2).unwrap(); + let act_3 = act_2_result.0; + let act_3_hex = hex::encode(&act_3.0.to_vec()); + assert_eq!(act_3_hex, "00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"); + + remote_handshake.process_act_three(act_3).unwrap(); } \ No newline at end of file diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index 748356a8f12..23807e840d3 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -1,3 +1,8 @@ +//! Everything that has to do with over-the-wire peer communication. +//! The handshake module exposes mechanisms to conduct inbound and outbound handshakes. +//! When a handshake completes, it returns an instance of Conduit. +//! Conduit enables message encryption and decryption, and automatically handles key rotation. + mod chacha; pub mod conduit; pub mod handshake; From 19b7700e86b3de2889b11e80e2a554a1f55c4bb6 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 12 Feb 2020 17:22:12 -0800 Subject: [PATCH 06/96] allocate act messages without vector prevarication --- lightning/src/ln/peers/handshake/mod.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 482b497149e..a53625891bf 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -252,11 +252,9 @@ impl PeerHandshake { let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); - let mut act_three_vec = [0u8].to_vec(); - act_three_vec.extend_from_slice(&tagged_encrypted_pubkey); - act_three_vec.extend_from_slice(authentication_tag.as_slice()); let mut act_three = [0u8; 66]; - act_three.copy_from_slice(act_three_vec.as_slice()); + act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); + act_three[50..].copy_from_slice(authentication_tag.as_slice()); let connected_peer = Conduit { sending_key, @@ -330,11 +328,10 @@ impl PeerHandshake { hash.update(&tagged_ciphertext); - let mut act_vec = [0u8].to_vec(); - act_vec.extend_from_slice(&local_public_key.serialize()); - act_vec.extend_from_slice(tagged_ciphertext.as_slice()); let mut act = [0u8; 50]; - act.copy_from_slice(act_vec.as_slice()); + act[1..34].copy_from_slice(&local_public_key.serialize()); + act[34..].copy_from_slice(tagged_ciphertext.as_slice()); + (act, chaining_key, temporary_key) } From 17fda756e529a02fcc3317162232e16b362db750 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 12 Feb 2020 17:29:43 -0800 Subject: [PATCH 07/96] reduce vector allocations for message encryption --- lightning/src/ln/peers/conduit.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 019d3c11d63..bf51d3ecbc3 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -3,7 +3,8 @@ use ln::peers::{chacha, hkdf}; use util::byte_utils; -/// Returned after a successful handshake to encrypt and decrypt communication with peer nodes +/// Returned after a successful handshake to encrypt and decrypt communication with peer nodes. +/// It should not normally be manually instantiated. /// Automatically handles key rotation. /// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering. pub struct Conduit { @@ -25,14 +26,14 @@ impl Conduit { let length = buffer.len() as u16; let length_bytes = byte_utils::be16_to_array(length); - let encrypted_length = chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes); + let mut ciphertext = vec![0u8; 18 + length as usize + 16]; + + ciphertext[0..18].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes)); self.increment_sending_nonce(); - let encrypted_message = chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer); + ciphertext[18..].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer)); self.increment_sending_nonce(); - let mut ciphertext = encrypted_length; - ciphertext.extend_from_slice(&encrypted_message); ciphertext } From 8169b3158db72fbdeed6ad87586ce04014b6ac5a Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 19 Feb 2020 11:14:47 -0800 Subject: [PATCH 08/96] address some of Jeff's comments pertaining to message decryption, constants, and type definitions respond to Jeff's comments and add node pubkeys to map simplify review by means of 3 scopes adjust scope indentation resolve merge conflicts respond to more of Jeff's comments constantify key rotation index for conduit --- lightning/src/ln/peer_handler.rs | 403 +++++++++++---------- lightning/src/ln/peers/chacha.rs | 3 +- lightning/src/ln/peers/conduit.rs | 87 +++-- lightning/src/ln/peers/handshake/acts.rs | 10 +- lightning/src/ln/peers/handshake/mod.rs | 73 ++-- lightning/src/ln/peers/handshake/states.rs | 2 +- 6 files changed, 302 insertions(+), 276 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 0aebdf1dc4e..f0c6dc6603f 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -108,16 +108,15 @@ enum InitSyncTracker{ } enum PeerState { - Handshake(PeerHandshake), + Authenticating(PeerHandshake), Connected(Conduit), } impl PeerState { fn is_ready_for_encryption(&self) -> bool { - if let &PeerState::Connected(_) = self { - true - } else { - false + match self { + &PeerState::Connected(_) => true, + _ => false } } } @@ -283,7 +282,7 @@ impl PeerManager where let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { - encryptor: PeerState::Handshake(handshake), + encryptor: PeerState::Authenticating(handshake), outbound: true, their_node_id: Some(their_node_id.clone()), their_features: None, @@ -318,7 +317,7 @@ impl PeerManager where let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { - encryptor: PeerState::Handshake(handshake), + encryptor: PeerState::Authenticating(handshake), outbound: false, their_node_id: None, their_features: None, @@ -469,9 +468,9 @@ impl PeerManager where let mut conduit_option = None; let mut remote_pubkey_option = None; - if let &mut PeerState::Handshake(ref mut handshake) = &mut peer.encryptor { + if let &mut PeerState::Authenticating(ref mut handshake) = &mut peer.encryptor { let (response, conduit, remote_pubkey) = handshake.process_act(&peer.pending_read_buffer, None).unwrap(); - peer.pending_read_buffer.drain(..); // we read it all + peer.pending_read_buffer = Vec::new(); // empty the pending read buffer if let Some(key) = remote_pubkey { remote_pubkey_option = Some(key); @@ -490,10 +489,22 @@ impl PeerManager where if let Some(conduit) = conduit_option { // Rust 1.22 does not allow assignment in a borrowed context, even if mutable peer.encryptor = PeerState::Connected(conduit); + + // the handshake has finished, so one way or another, we now have their node id + match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { + hash_map::Entry::Occupied(_) => { + log_trace!(self, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); + peer.their_node_id = None; // Unset so that we don't generate a peer_disconnected event + return Err(PeerHandleError{ no_connection_possible: false }) + }, + hash_map::Entry::Vacant(entry) => { + log_trace!(self, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); + entry.insert(peer_descriptor.clone()) + }, + }; } if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { - macro_rules! encode_and_send_msg { ($msg: expr) => { { @@ -531,211 +542,211 @@ impl PeerManager where } } - let mut next_message_result = conduit.decrypt(&peer.pending_read_buffer); - - let offset = next_message_result.1; - if offset == 0 { - // nothing got read + let message_option = conduit.decrypt_single_message(Some(&peer.pending_read_buffer.clone())); + peer.pending_read_buffer = Vec::new(); // empty the pending read buffer + let msg_data = if let Some(message) = message_option { + message + } else { break; - }else{ - peer.pending_read_buffer.drain(0..offset); - } - - // something got read, so we definitely have a message - let msg_data = next_message_result.0.unwrap(); - - let mut reader = ::std::io::Cursor::new(&msg_data[..]); - let message_result = wire::read(&mut reader); - let message = match message_result { - Ok(x) => x, - Err(e) => { - match e { - msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to update!"); - continue; - } - msgs::DecodeError::InvalidValue => { - log_debug!(self, "Got an invalid value while deserializing message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ShortRead => { - log_debug!(self, "Deserialization failed due to shortness of message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ExtraAddressesPerType => { - log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407"); - continue; - } - msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), - } - } }; - log_trace!(self, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - - // Need an Init as first message - if let wire::Message::Init(_) = message { - } else if peer.their_features.is_none() { - log_trace!(self, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); - return Err(PeerHandleError{ no_connection_possible: false }); - } - - match message { - // Setup and Control messages: - wire::Message::Init(msg) => { - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer global features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }); - } - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer local features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }); - } - if peer.their_features.is_some() { - return Err(PeerHandleError{ no_connection_possible: false }); - } - - log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", - if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, - if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, - if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, - if msg.features.supports_unknown_bits() { "present" } else { "none" }, - if msg.features.supports_unknown_bits() { "present" } else { "none" }); + { + { + { + let mut reader = ::std::io::Cursor::new(&msg_data[..]); + let message_result = wire::read(&mut reader); + let message = match message_result { + Ok(x) => x, + Err(e) => { + match e { + msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::UnknownRequiredFeature => { + log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + continue; + } + msgs::DecodeError::InvalidValue => { + log_debug!(self, "Got an invalid value while deserializing message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ShortRead => { + log_debug!(self, "Deserialization failed due to shortness of message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ExtraAddressesPerType => { + log_debug!(self, "Error decoding message, ignoring due to lnd spec incompatibility. See https://github.com/lightningnetwork/lnd/issues/1407"); + continue; + } + msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), + } + } + }; - if msg.features.initial_routing_sync() { - peer.sync_status = InitSyncTracker::ChannelsSyncing(0); - peers.peers_needing_send.insert(peer_descriptor.clone()); - } + log_trace!(self, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - if !peer.outbound { - let mut features = InitFeatures::supported(); - if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.set_initial_routing_sync(); + // Need an Init as first message + if let wire::Message::Init(_) = message {} else if peer.their_features.is_none() { + log_trace!(self, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); + return Err(PeerHandleError { no_connection_possible: false }); } - let resp = msgs::Init { features }; - encode_and_send_msg!(resp); - } - - self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); - peer.their_features = Some(msg.features); - }, - wire::Message::Error(msg) => { - let mut data_is_printable = true; - for b in msg.data.bytes() { - if b < 32 || b > 126 { - data_is_printable = false; - break; - } - } + match message { + // Setup and Control messages: + wire::Message::Init(msg) => { + if msg.features.requires_unknown_bits() { + log_info!(self, "Peer global features required unknown version bits"); + return Err(PeerHandleError { no_connection_possible: true }); + } + if msg.features.requires_unknown_bits() { + log_info!(self, "Peer local features required unknown version bits"); + return Err(PeerHandleError { no_connection_possible: true }); + } + if peer.their_features.is_some() { + return Err(PeerHandleError { no_connection_possible: false }); + } + + log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", + if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, + if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, + if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, + if msg.features.supports_unknown_bits() { "present" } else { "none" }, + if msg.features.supports_unknown_bits() { "present" } else { "none" }); + + if msg.features.initial_routing_sync() { + peer.sync_status = InitSyncTracker::ChannelsSyncing(0); + peers.peers_needing_send.insert(peer_descriptor.clone()); + } + + if !peer.outbound { + let mut features = InitFeatures::supported(); + if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.set_initial_routing_sync(); + } + + let resp = msgs::Init { features }; + encode_and_send_msg!(resp); + } + + self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); + peer.their_features = Some(msg.features); + } + wire::Message::Error(msg) => { + let mut data_is_printable = true; + for b in msg.data.bytes() { + if b < 32 || b > 126 { + data_is_printable = false; + break; + } + } + + if data_is_printable { + log_debug!(self, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); + } else { + log_debug!(self, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); + } + self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); + if msg.channel_id == [0; 32] { + return Err(PeerHandleError { no_connection_possible: true }); + } + } - if data_is_printable { - log_debug!(self, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); - } else { - log_debug!(self, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); - } - self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); - if msg.channel_id == [0; 32] { - return Err(PeerHandleError{ no_connection_possible: true }); - } - }, + wire::Message::Ping(msg) => { + if msg.ponglen < 65532 { + let resp = msgs::Pong { byteslen: msg.ponglen }; + encode_and_send_msg!(resp); + } + } + wire::Message::Pong(_msg) => { + peer.awaiting_pong = false; + } - wire::Message::Ping(msg) => { - if msg.ponglen < 65532 { - let resp = msgs::Pong { byteslen: msg.ponglen }; - encode_and_send_msg!(resp); - } - }, - wire::Message::Pong(_msg) => { - peer.awaiting_pong = false; - }, + // Channel messages: + wire::Message::OpenChannel(msg) => { + self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + } + wire::Message::AcceptChannel(msg) => { + self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + } - // Channel messages: - wire::Message::OpenChannel(msg) => { - self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - }, - wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - }, + wire::Message::FundingCreated(msg) => { + self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::FundingSigned(msg) => { + self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::FundingLocked(msg) => { + self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); + } - wire::Message::FundingCreated(msg) => { - self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::FundingSigned(msg) => { - self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::FundingLocked(msg) => { - self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); - }, + wire::Message::Shutdown(msg) => { + self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::ClosingSigned(msg) => { + self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); + } - wire::Message::Shutdown(msg) => { - self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::ClosingSigned(msg) => { - self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); - }, + // Commitment messages: + wire::Message::UpdateAddHTLC(msg) => { + self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFulfillHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFailHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFailMalformedHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); + } - // Commitment messages: - wire::Message::UpdateAddHTLC(msg) => { - self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFulfillHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFailHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFailMalformedHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); - }, + wire::Message::CommitmentSigned(msg) => { + self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::RevokeAndACK(msg) => { + self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFee(msg) => { + self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::ChannelReestablish(msg) => { + self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); + } - wire::Message::CommitmentSigned(msg) => { - self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::RevokeAndACK(msg) => { - self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::UpdateFee(msg) => { - self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::ChannelReestablish(msg) => { - self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); - }, + // Routing messages: + wire::Message::AnnouncementSignatures(msg) => { + self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::ChannelAnnouncement(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); - // Routing messages: - wire::Message::AnnouncementSignatures(msg) => { - self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); - }, - wire::Message::ChannelAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); + if should_forward { + // TODO: forward msg along to all our other peers! + } + } + wire::Message::NodeAnnouncement(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); - if should_forward { - // TODO: forward msg along to all our other peers! - } - }, - wire::Message::NodeAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); + if should_forward { + // TODO: forward msg along to all our other peers! + } + } + wire::Message::ChannelUpdate(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); - if should_forward { - // TODO: forward msg along to all our other peers! - } - }, - wire::Message::ChannelUpdate(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); + if should_forward { + // TODO: forward msg along to all our other peers! + } + } - if should_forward { - // TODO: forward msg along to all our other peers! + // Unknown messages: + wire::Message::Unknown(msg_type) if msg_type.is_even() => { + // Fail the channel if message is an even, unknown type as per BOLT #1. + return Err(PeerHandleError { no_connection_possible: true }); + } + wire::Message::Unknown(_) => {} + } } - }, - - // Unknown messages: - wire::Message::Unknown(msg_type) if msg_type.is_even() => { - // Fail the channel if message is an even, unknown type as per BOLT #1. - return Err(PeerHandleError{ no_connection_possible: true }); - }, - wire::Message::Unknown(_) => {}, + } } } diff --git a/lightning/src/ln/peers/chacha.rs b/lightning/src/ln/peers/chacha.rs index e82e55a91c6..4e8d948706f 100644 --- a/lightning/src/ln/peers/chacha.rs +++ b/lightning/src/ln/peers/chacha.rs @@ -1,6 +1,8 @@ use util::byte_utils; use util::chacha20poly1305rfc::ChaCha20Poly1305RFC; +pub const TAG_SIZE: usize = 16; + pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) -> Vec { let mut nonce_bytes = [0; 12]; nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce)); @@ -15,7 +17,6 @@ pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) tagged_ciphertext } - pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext: &[u8]) -> Result, String> { let mut nonce_bytes = [0; 12]; nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce)); diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index bf51d3ecbc3..2fcec64fc05 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -3,16 +3,23 @@ use ln::peers::{chacha, hkdf}; use util::byte_utils; +pub(super) type SymmetricKey = [u8; 32]; + +const MESSAGE_LENGTH_HEADER_SIZE: usize = 2; +const TAGGED_MESSAGE_LENGTH_HEADER_SIZE: usize = MESSAGE_LENGTH_HEADER_SIZE + chacha::TAG_SIZE; + +const KEY_ROTATION_INDEX: u32 = 1000; + /// Returned after a successful handshake to encrypt and decrypt communication with peer nodes. /// It should not normally be manually instantiated. /// Automatically handles key rotation. /// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering. pub struct Conduit { - pub(crate) sending_key: [u8; 32], - pub(crate) receiving_key: [u8; 32], + pub(crate) sending_key: SymmetricKey, + pub(crate) receiving_key: SymmetricKey, - pub(crate) sending_chaining_key: [u8; 32], - pub(crate) receiving_chaining_key: [u8; 32], + pub(crate) sending_chaining_key: SymmetricKey, + pub(crate) receiving_chaining_key: SymmetricKey, pub(crate) receiving_nonce: u32, pub(crate) sending_nonce: u32, @@ -26,24 +33,27 @@ impl Conduit { let length = buffer.len() as u16; let length_bytes = byte_utils::be16_to_array(length); - let mut ciphertext = vec![0u8; 18 + length as usize + 16]; + let mut ciphertext = vec![0u8; TAGGED_MESSAGE_LENGTH_HEADER_SIZE + length as usize + chacha::TAG_SIZE]; - ciphertext[0..18].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes)); + ciphertext[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes)); self.increment_sending_nonce(); - ciphertext[18..].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer)); + ciphertext[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer)); self.increment_sending_nonce(); ciphertext } pub(super) fn read(&mut self, data: &[u8]) { - let mut read_buffer = self.read_buffer.get_or_insert(Vec::new()); + let read_buffer = self.read_buffer.get_or_insert(Vec::new()); read_buffer.extend_from_slice(data); } - /// Add newly received data from the peer node to the buffer and decrypt all possible messages - pub fn decrypt_message_stream(&mut self, new_data: Option<&[u8]>) -> Vec> { + /// Decrypt a single message. If data containing more than one message has been received, + /// only the first message will be returned, and the rest stored in the internal buffer. + /// If a message pending in the buffer still hasn't been decrypted, that message will be + /// returned in lieu of anything new, even if new data is provided. + pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Option> { let mut read_buffer = if let Some(buffer) = self.read_buffer.take() { buffer } else { @@ -54,45 +64,34 @@ impl Conduit { read_buffer.extend_from_slice(data); } - let mut messages = Vec::new(); - - loop { - // todo: find way that won't require cloning the entire buffer - let (current_message, offset) = self.decrypt(&read_buffer[..]); - if offset == 0 { - break; - } - - read_buffer.drain(0..offset); + let (current_message, offset) = self.decrypt(&read_buffer[..]); + read_buffer.drain(0..offset); // drain the read buffer + self.read_buffer = Some(read_buffer); // assign the new value to the built-in buffer - if let Some(message) = current_message { - messages.push(message); - } else { - break; - } + if offset == 0 { + return None; } - messages + current_message } - /// Decrypt a single message. Buffer is an undelimited amount of bytes pub(crate) fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { // the response slice should have the same lifetime as the argument. It's the slice data is read from - if buffer.len() < 18 { + if buffer.len() < TAGGED_MESSAGE_LENGTH_HEADER_SIZE { return (None, 0); } - let encrypted_length = &buffer[0..18]; // todo: abort if too short + let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; // todo: abort if too short let length_vec = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap(); - let mut length_bytes = [0u8; 2]; + let mut length_bytes = [0u8; MESSAGE_LENGTH_HEADER_SIZE]; length_bytes.copy_from_slice(length_vec.as_slice()); let message_length = byte_utils::slice_to_be16(&length_bytes) as usize; - let message_end_index = message_length + 18 + 16; // todo: abort if too short + let message_end_index = TAGGED_MESSAGE_LENGTH_HEADER_SIZE + message_length + chacha::TAG_SIZE; // todo: abort if too short if buffer.len() < message_end_index { return (None, 0); } - let encrypted_message = &buffer[18..message_end_index]; + let encrypted_message = &buffer[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..message_end_index]; self.increment_receiving_nonce(); @@ -111,15 +110,15 @@ impl Conduit { Self::increment_nonce(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); } - fn increment_nonce(nonce: &mut u32, chaining_key: &mut [u8; 32], key: &mut [u8; 32]) { + fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { *nonce += 1; - if *nonce == 1000 { + if *nonce == KEY_ROTATION_INDEX { Self::rotate_key(chaining_key, key); *nonce = 0; } } - fn rotate_key(chaining_key: &mut [u8; 32], key: &mut [u8; 32]) { + fn rotate_key(chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { let (new_chaining_key, new_key) = hkdf::derive(chaining_key, key); chaining_key.copy_from_slice(&new_chaining_key); key.copy_from_slice(&new_key); @@ -132,6 +131,7 @@ mod tests { use ln::peers::conduit::Conduit; #[test] + /// Based on RFC test vectors: https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#message-encryption-tests fn test_chaining() { let chaining_key_vec = hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap(); let mut chaining_key = [0u8; 32]; @@ -180,11 +180,18 @@ mod tests { assert_eq!(encrypted_messages[1000], hex::decode("4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09").unwrap()); assert_eq!(encrypted_messages[1001], hex::decode("2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36").unwrap()); - for _ in 0..1002 { - let encrypted_message = encrypted_messages.remove(0); - let mut decrypted_messages = remote_peer.decrypt_message_stream(Some(&encrypted_message)); - assert_eq!(decrypted_messages.len(), 1); - let decrypted_message = decrypted_messages.remove(0); + for _ in 0..501 { + // read two messages at once, filling buffer + let mut current_encrypted_message = encrypted_messages.remove(0); + let mut next_encrypted_message = encrypted_messages.remove(0); + current_encrypted_message.extend_from_slice(&next_encrypted_message); + let decrypted_message = remote_peer.decrypt_single_message(Some(¤t_encrypted_message)).unwrap(); + assert_eq!(decrypted_message, hex::decode("68656c6c6f").unwrap()); + } + + for _ in 0..501 { + // decrypt messages directly from buffer without adding to it + let decrypted_message = remote_peer.decrypt_single_message(None).unwrap(); assert_eq!(decrypted_message, hex::decode("68656c6c6f").unwrap()); } } diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs index 93e582908a7..4f29d0e4f8d 100644 --- a/lightning/src/ln/peers/handshake/acts.rs +++ b/lightning/src/ln/peers/handshake/acts.rs @@ -1,16 +1,20 @@ +pub const ACT_ONE_LENGTH: usize = 50; +pub const ACT_TWO_LENGTH: usize = 50; +pub const ACT_THREE_LENGTH: usize = 66; + /// Wrapper for the first act message pub struct ActOne( - pub(super) [u8; 50] + pub(super) [u8; ACT_ONE_LENGTH] ); /// Wrapper for the second act message pub struct ActTwo( - pub(super) [u8; 50] + pub(super) [u8; ACT_TWO_LENGTH] ); /// Wrapper for the third act message pub struct ActThree( - pub(super) [u8; 66] + pub(super) [u8; ACT_THREE_LENGTH] ); /// Wrapper for any act message diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index a53625891bf..fd9380f8fec 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -9,8 +9,8 @@ use bitcoin_hashes::sha256::Hash as Sha256; use secp256k1::{PublicKey, SecretKey}; use ln::peers::{chacha, hkdf}; -use ln::peers::conduit::Conduit; -use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo}; +use ln::peers::conduit::{Conduit, SymmetricKey}; +use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH}; use ln::peers::handshake::hash::HandshakeHash; use ln::peers::handshake::states::{ActOneExpectation, ActThreeExpectation, ActTwoExpectation, HandshakeState}; @@ -32,13 +32,12 @@ pub struct PeerHandshake { impl PeerHandshake { /// Instantiate a new handshake with a node identity secret key and an ephemeral private key pub fn new(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { - let handshake = PeerHandshake { - state: Some(HandshakeState::Blank), + Self { + state: Some(HandshakeState::Uninitiated), private_key: (*private_key).clone(), ephemeral_private_key: (*ephemeral_private_key).clone(), read_buffer: Vec::new(), - }; - handshake + } } /// Make the handshake object inbound in anticipation of a peer's first handshake act @@ -52,7 +51,6 @@ impl PeerHandshake { } fn initialize_state(public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { - // do the proper initialization let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; let prologue = b"lightning"; @@ -66,11 +64,19 @@ impl PeerHandshake { let mut hash = HandshakeHash::new(initial_hash_preimage.as_slice()); hash.update(&public_key.serialize()); - (hash, chaining_key) // hash, chaining_key + (hash, chaining_key) } /// Process act dynamically - /// The role must be set before this method can be called + /// # Arguments + /// `input`: Byte slice received from peer as part of the handshake protocol + /// `remote_public_key`: If outbound, the peer's static identity public key needs is required for the handshake initiation + /// + /// # Return values + /// Returns a tuple with the following components: + /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol + /// `.1`: Conduit option if the handshake was just processed to completion and messages can now be encrypted and decrypted + /// `.2`: Public key option if the handshake was inbound and the peer's static identity pubkey was just learned pub fn process_act(&mut self, input: &[u8], remote_public_key: Option<&PublicKey>) -> Result<(Vec, Option, Option), String> { let mut response: Vec = Vec::new(); let mut connected_peer = None; @@ -80,7 +86,7 @@ impl PeerHandshake { let read_buffer_length = self.read_buffer.len(); match &self.state { - &Some(HandshakeState::Blank) => { + &Some(HandshakeState::Uninitiated) => { let remote_public_key = remote_public_key.ok_or("remote_public_key must be Some for outbound connections")?; let act_one = self.initiate(&remote_public_key)?; response = act_one.0.to_vec(); @@ -91,22 +97,21 @@ impl PeerHandshake { return Err("need at least 50 bytes".to_string()); } - let mut act_one_buffer = [0u8; 50]; - act_one_buffer.copy_from_slice(&self.read_buffer[..act_length]); - self.read_buffer.drain(..act_length); + let mut act_one_buffer = [0u8; ACT_ONE_LENGTH]; + act_one_buffer.copy_from_slice(&self.read_buffer[..ACT_ONE_LENGTH]); + self.read_buffer.drain(..ACT_ONE_LENGTH); let act_two = self.process_act_one(ActOne(act_one_buffer))?; response = act_two.0.to_vec(); } &Some(HandshakeState::AwaitingActTwo(_)) => { - let act_length = 50; - if read_buffer_length < act_length { + if read_buffer_length < ACT_TWO_LENGTH { return Err("need at least 50 bytes".to_string()); } - let mut act_two_buffer = [0u8; 50]; - act_two_buffer.copy_from_slice(&self.read_buffer[..act_length]); - self.read_buffer.drain(..act_length); + let mut act_two_buffer = [0u8; ACT_TWO_LENGTH]; + act_two_buffer.copy_from_slice(&self.read_buffer[..ACT_TWO_LENGTH]); + self.read_buffer.drain(..ACT_TWO_LENGTH); let (act_three, mut conduit) = self.process_act_two(ActTwo(act_two_buffer))?; @@ -119,14 +124,13 @@ impl PeerHandshake { connected_peer = Some(conduit); } &Some(HandshakeState::AwaitingActThree(_)) => { - let act_length = 66; - if read_buffer_length < act_length { - return Err("need at least 50 bytes".to_string()); + if read_buffer_length < ACT_THREE_LENGTH { + return Err("need at least 66 bytes".to_string()); } - let mut act_three_buffer = [0u8; 66]; - act_three_buffer.copy_from_slice(&self.read_buffer[..act_length]); - self.read_buffer.drain(..act_length); + let mut act_three_buffer = [0u8; ACT_THREE_LENGTH]; + act_three_buffer.copy_from_slice(&self.read_buffer[..ACT_THREE_LENGTH]); + self.read_buffer.drain(..ACT_THREE_LENGTH); let (public_key, mut conduit) = self.process_act_three(ActThree(act_three_buffer))?; @@ -147,14 +151,14 @@ impl PeerHandshake { /// Initiate the handshake with a peer and return the first act pub fn initiate(&mut self, remote_public_key: &PublicKey) -> Result { - if let &Some(HandshakeState::Blank) = &self.state {} else { + if let &Some(HandshakeState::Uninitiated) = &self.state {} else { return Err("incorrect state".to_string()); } let (mut hash, chaining_key) = Self::initialize_state(&remote_public_key); // serialize act one - let (act_one, chaining_key, temporary_key) = self.calculate_act_message( + let (act_one, chaining_key, temporary_key) = Self::calculate_act_message( &self.ephemeral_private_key, remote_public_key, chaining_key, @@ -176,9 +180,8 @@ impl PeerHandshake { let state = self.state.take(); let act_one_expectation = match state { Some(HandshakeState::AwaitingActOne(act_state)) => act_state, - Some(HandshakeState::Blank) => { + Some(HandshakeState::Uninitiated) => { // this can also be initiated from a blank state - // public key let public_key = Self::private_key_to_public_key(&self.private_key); let (hash, chaining_key) = Self::initialize_state(&public_key); ActOneExpectation { @@ -193,7 +196,7 @@ impl PeerHandshake { }; let mut hash = act_one_expectation.hash; - let (remote_ephemeral_public_key, chaining_key, _) = self.process_act_message( + let (remote_ephemeral_public_key, chaining_key, _) = Self::process_act_message( act.0, &self.private_key, act_one_expectation.chaining_key, @@ -202,7 +205,7 @@ impl PeerHandshake { let ephemeral_private_key = (*&self.ephemeral_private_key).clone(); - let (act_two, chaining_key, temporary_key) = self.calculate_act_message( + let (act_two, chaining_key, temporary_key) = Self::calculate_act_message( &ephemeral_private_key, &remote_ephemeral_public_key, chaining_key, @@ -232,7 +235,7 @@ impl PeerHandshake { }; let mut hash = act_two_expectation.hash; - let (remote_ephemeral_public_key, chaining_key, temporary_key) = self.process_act_message( + let (remote_ephemeral_public_key, chaining_key, temporary_key) = Self::process_act_message( act.0, &act_two_expectation.ephemeral_private_key, act_two_expectation.chaining_key, @@ -317,7 +320,7 @@ impl PeerHandshake { Ok((remote_pubkey, connected_peer)) } - fn calculate_act_message(&self, local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], [u8; 32], [u8; 32]) { + fn calculate_act_message(local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { let local_public_key = Self::private_key_to_public_key(local_private_key); hash.update(&local_public_key.serialize()); @@ -335,7 +338,7 @@ impl PeerHandshake { (act, chaining_key, temporary_key) } - fn process_act_message(&self, act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> Result<(PublicKey, [u8; 32], [u8; 32]), String> { + fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { let version = act_bytes[0]; if version != 0 { return Err("unexpected version".to_string()); @@ -360,7 +363,7 @@ impl PeerHandshake { // HKDF(chaining key, ECDH) -> chaining key' + next temporary key let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - // Validate chacha tag (temporary key, 0, self.hash, chacha_tag) + // Validate chacha tag (temporary key, 0, hash, chacha_tag) let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; hash.update(&chacha_tag); @@ -374,7 +377,7 @@ impl PeerHandshake { pk_object } - fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> [u8; 32] { + fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> SymmetricKey { let curve = secp256k1::Secp256k1::new(); let mut pk_object = public_key.clone(); pk_object.mul_assign(&curve, &private_key[..]).expect("invalid multiplication"); diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 836be023a0d..643d7b16f9a 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -2,7 +2,7 @@ use ln::peers::handshake::hash::HandshakeHash; use secp256k1::{SecretKey, PublicKey}; pub enum HandshakeState { - Blank, + Uninitiated, AwaitingActOne(ActOneExpectation), AwaitingActTwo(ActTwoExpectation), AwaitingActThree(ActThreeExpectation), From f1002c5493b999d51a285e0d753ac451b623d54d Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 19 Feb 2020 15:47:26 -0800 Subject: [PATCH 09/96] Use type standin for remaining act lengths when parsing. Use the same handshake method `process_act` across both call sites from peer_handler.rs. --- lightning/src/ln/peer_handler.rs | 3 +-- lightning/src/ln/peers/conduit.rs | 6 +++--- lightning/src/ln/peers/handshake/mod.rs | 5 ++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index f0c6dc6603f..8121a7465ef 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -277,8 +277,7 @@ impl PeerManager where /// disconnect_event. pub fn new_outbound_connection(&self, their_node_id: PublicKey, descriptor: Descriptor) -> Result, PeerHandleError> { let mut handshake = PeerHandshake::new(&self.our_node_secret, &self.get_ephemeral_key()); - let act_one = handshake.initiate(&their_node_id).unwrap(); - let res = Act::One(act_one).serialize(); + let (res, ..) = handshake.process_act(&[], Some(&their_node_id)).unwrap(); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 2fcec64fc05..e3275dcd447 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -75,15 +75,15 @@ impl Conduit { current_message } - pub(crate) fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { // the response slice should have the same lifetime as the argument. It's the slice data is read from + /// Decrypt a message from the beginning of the provided buffer. Returns the consumed number of bytes. + fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { if buffer.len() < TAGGED_MESSAGE_LENGTH_HEADER_SIZE { return (None, 0); } let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; // todo: abort if too short - let length_vec = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap(); let mut length_bytes = [0u8; MESSAGE_LENGTH_HEADER_SIZE]; - length_bytes.copy_from_slice(length_vec.as_slice()); + length_bytes.copy_from_slice(&chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap()); let message_length = byte_utils::slice_to_be16(&length_bytes) as usize; let message_end_index = TAGGED_MESSAGE_LENGTH_HEADER_SIZE + message_length + chacha::TAG_SIZE; // todo: abort if too short diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index fd9380f8fec..a97aacad4bc 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -92,8 +92,7 @@ impl PeerHandshake { response = act_one.0.to_vec(); } &Some(HandshakeState::AwaitingActOne(_)) => { - let act_length = 50; - if read_buffer_length < act_length { + if read_buffer_length < ACT_ONE_LENGTH { return Err("need at least 50 bytes".to_string()); } @@ -152,7 +151,7 @@ impl PeerHandshake { /// Initiate the handshake with a peer and return the first act pub fn initiate(&mut self, remote_public_key: &PublicKey) -> Result { if let &Some(HandshakeState::Uninitiated) = &self.state {} else { - return Err("incorrect state".to_string()); + return Err("Handshakes can only be initiated from the uninitiated state".to_string()); } let (mut hash, chaining_key) = Self::initialize_state(&remote_public_key); From f0fc10b08468793efbd21bfe35acbba89fb42132 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 20 Feb 2020 10:00:03 -0800 Subject: [PATCH 10/96] Improve comments and type aliasing for handshake module. --- lightning/src/ln/peers/handshake/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index a97aacad4bc..1b415ffad34 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -337,7 +337,8 @@ impl PeerHandshake { (act, chaining_key, temporary_key) } - fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { + // Due to the very high similarity of acts 1 and 2, this method is used to process both + fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { let version = act_bytes[0]; if version != 0 { return Err("unexpected version".to_string()); From 256b6f578b0ca9ff9ecd1325ea2ac768b221c4d5 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 20 Feb 2020 12:23:43 -0800 Subject: [PATCH 11/96] Reflect new modular encryption mechanism in tock ping message creation. --- lightning/src/ln/peer_handler.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 73008ee7b00..85e5bdb4a81 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -1115,21 +1115,19 @@ impl PeerManager where return false; } - if !peer.channel_encryptor.is_ready_for_encryption() { - // The peer needs to complete its handshake before we can exchange messages - return true; - } + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + let ping = msgs::Ping { + ponglen: 0, + byteslen: 64, + }; + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(&ping))); - let ping = msgs::Ping { - ponglen: 0, - byteslen: 64, - }; - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!(&ping))); + let mut descriptor_clone = descriptor.clone(); + self.do_attempt_write_data(&mut descriptor_clone, peer); - let mut descriptor_clone = descriptor.clone(); - self.do_attempt_write_data(&mut descriptor_clone, peer); + peer.awaiting_pong = true; + } - peer.awaiting_pong = true; true }); } From b4921e900a31f4a02c12a00c6a4dd26ab6c8d686 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 20 Feb 2020 19:13:23 -0800 Subject: [PATCH 12/96] Elaborate on lightning codec in conduit's decrypt method. --- lightning/src/ln/peer_handler.rs | 7 +++++-- lightning/src/ln/peers/conduit.rs | 6 ++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 85e5bdb4a81..9c13f74be59 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -1115,19 +1115,22 @@ impl PeerManager where return false; } + let mut needs_to_write_data = false; if let PeerState::Connected(ref mut conduit) = peer.encryptor { let ping = msgs::Ping { ponglen: 0, byteslen: 64, }; peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(&ping))); + needs_to_write_data = true; + } + if needs_to_write_data { let mut descriptor_clone = descriptor.clone(); self.do_attempt_write_data(&mut descriptor_clone, peer); - - peer.awaiting_pong = true; } + peer.awaiting_pong = true; true }); } diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index e3275dcd447..b7fd882b2d5 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -78,15 +78,17 @@ impl Conduit { /// Decrypt a message from the beginning of the provided buffer. Returns the consumed number of bytes. fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { if buffer.len() < TAGGED_MESSAGE_LENGTH_HEADER_SIZE { + // A message must be at least 18 bytes (2 for encrypted length, 16 for the tag) return (None, 0); } - let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; // todo: abort if too short + let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; let mut length_bytes = [0u8; MESSAGE_LENGTH_HEADER_SIZE]; length_bytes.copy_from_slice(&chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap()); + // message_length is the length of the encrypted message excluding its trailing 16-byte tag let message_length = byte_utils::slice_to_be16(&length_bytes) as usize; - let message_end_index = TAGGED_MESSAGE_LENGTH_HEADER_SIZE + message_length + chacha::TAG_SIZE; // todo: abort if too short + let message_end_index = TAGGED_MESSAGE_LENGTH_HEADER_SIZE + message_length + chacha::TAG_SIZE; if buffer.len() < message_end_index { return (None, 0); } From 299b6f734e5eedb1827f3dfa04a90d1cd9da9ed8 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Fri, 21 Feb 2020 11:03:02 -0800 Subject: [PATCH 13/96] Split up conduit unit tests by tested functionality. --- lightning/src/ln/peers/conduit.rs | 67 ++++++++++++++++++++++++------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index b7fd882b2d5..9d848f45b8f 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -65,13 +65,8 @@ impl Conduit { } let (current_message, offset) = self.decrypt(&read_buffer[..]); - read_buffer.drain(0..offset); // drain the read buffer + read_buffer.drain(..offset); // drain the read buffer self.read_buffer = Some(read_buffer); // assign the new value to the built-in buffer - - if offset == 0 { - return None; - } - current_message } @@ -132,9 +127,7 @@ mod tests { use hex; use ln::peers::conduit::Conduit; - #[test] - /// Based on RFC test vectors: https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#message-encryption-tests - fn test_chaining() { + fn setup_peers() -> (Conduit, Conduit) { let chaining_key_vec = hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap(); let mut chaining_key = [0u8; 32]; chaining_key.copy_from_slice(&chaining_key_vec); @@ -147,7 +140,7 @@ mod tests { let mut receiving_key = [0u8; 32]; receiving_key.copy_from_slice(&receiving_key_vec); - let mut connected_peer = Conduit { + let connected_peer = Conduit { sending_key, receiving_key, sending_chaining_key: chaining_key, @@ -157,7 +150,7 @@ mod tests { read_buffer: None, }; - let mut remote_peer = Conduit { + let remote_peer = Conduit { sending_key: receiving_key, receiving_key: sending_key, sending_chaining_key: chaining_key, @@ -167,6 +160,39 @@ mod tests { read_buffer: None, }; + (connected_peer, remote_peer) + } + + #[test] + fn test_empty_message() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + + let message: Vec = vec![]; + let encrypted_message = connected_peer.encrypt(&message); + assert_eq!(encrypted_message.len(), 2 + 16 + 16); + + let decrypted_message = remote_peer.decrypt_single_message(Some(&encrypted_message)).unwrap(); + assert_eq!(decrypted_message, vec![]); + } + + #[test] + fn test_nonce_chaining() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let message = hex::decode("68656c6c6f").unwrap(); + + let encrypted_message = connected_peer.encrypt(&message); + assert_eq!(encrypted_message, hex::decode("cf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95").unwrap()); + + // the second time the same message is encrypted, the ciphertext should be different + let encrypted_message = connected_peer.encrypt(&message); + assert_eq!(encrypted_message, hex::decode("72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1").unwrap()); + } + + #[test] + /// Based on RFC test vectors: https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#message-encryption-tests + fn test_key_rotation() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let message = hex::decode("68656c6c6f").unwrap(); let mut encrypted_messages: Vec> = Vec::new(); @@ -175,12 +201,23 @@ mod tests { encrypted_messages.push(encrypted_message); } - assert_eq!(encrypted_messages[0], hex::decode("cf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95").unwrap()); - assert_eq!(encrypted_messages[1], hex::decode("72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1").unwrap()); assert_eq!(encrypted_messages[500], hex::decode("178cb9d7387190fa34db9c2d50027d21793c9bc2d40b1e14dcf30ebeeeb220f48364f7a4c68bf8").unwrap()); assert_eq!(encrypted_messages[501], hex::decode("1b186c57d44eb6de4c057c49940d79bb838a145cb528d6e8fd26dbe50a60ca2c104b56b60e45bd").unwrap()); assert_eq!(encrypted_messages[1000], hex::decode("4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09").unwrap()); assert_eq!(encrypted_messages[1001], hex::decode("2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36").unwrap()); + } + + #[test] + fn test_decryption_buffering() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + + let message = hex::decode("68656c6c6f").unwrap(); + let mut encrypted_messages: Vec> = Vec::new(); + + for _ in 0..1002 { + let encrypted_message = connected_peer.encrypt(&message); + encrypted_messages.push(encrypted_message); + } for _ in 0..501 { // read two messages at once, filling buffer @@ -188,13 +225,13 @@ mod tests { let mut next_encrypted_message = encrypted_messages.remove(0); current_encrypted_message.extend_from_slice(&next_encrypted_message); let decrypted_message = remote_peer.decrypt_single_message(Some(¤t_encrypted_message)).unwrap(); - assert_eq!(decrypted_message, hex::decode("68656c6c6f").unwrap()); + assert_eq!(decrypted_message, message); } for _ in 0..501 { // decrypt messages directly from buffer without adding to it let decrypted_message = remote_peer.decrypt_single_message(None).unwrap(); - assert_eq!(decrypted_message, hex::decode("68656c6c6f").unwrap()); + assert_eq!(decrypted_message, message); } } } \ No newline at end of file From 944177a0843e6ad8a605f92323fa582fe7ccf0bb Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Fri, 21 Feb 2020 11:35:54 -0800 Subject: [PATCH 14/96] Make handshake store the remote public key instead of passing an option to the process_act method, which now also returns an enum of the next act instead of a Vec. --- lightning/src/ln/peer_handler.rs | 17 ++++---- lightning/src/ln/peers/handshake/mod.rs | 47 +++++++++++++++-------- lightning/src/ln/peers/handshake/tests.rs | 6 +-- 3 files changed, 44 insertions(+), 26 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 9c13f74be59..c20503fed9c 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -276,8 +276,9 @@ impl PeerManager where /// Panics if descriptor is duplicative with some other descriptor which has not yet has a /// disconnect_event. pub fn new_outbound_connection(&self, their_node_id: PublicKey, descriptor: Descriptor) -> Result, PeerHandleError> { - let mut handshake = PeerHandshake::new(&self.our_node_secret, &self.get_ephemeral_key()); - let (res, ..) = handshake.process_act(&[], Some(&their_node_id)).unwrap(); + let mut handshake = PeerHandshake::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); + let (act, ..) = handshake.process_act(&[]).unwrap(); + let res = act.unwrap().serialize(); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { @@ -311,8 +312,7 @@ impl PeerManager where /// Panics if descriptor is duplicative with some other descriptor which has not yet has a /// disconnect_event. pub fn new_inbound_connection(&self, descriptor: Descriptor) -> Result<(), PeerHandleError> { - let mut handshake = PeerHandshake::new(&self.our_node_secret, &self.get_ephemeral_key()); - handshake.make_inbound(); + let handshake = PeerHandshake::new_inbound(&self.our_node_secret, &self.get_ephemeral_key()); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { @@ -468,14 +468,17 @@ impl PeerManager where let mut remote_pubkey_option = None; if let &mut PeerState::Authenticating(ref mut handshake) = &mut peer.encryptor { - let (response, conduit, remote_pubkey) = handshake.process_act(&peer.pending_read_buffer, None).unwrap(); + let (next_act, conduit) = handshake.process_act(&peer.pending_read_buffer).unwrap(); peer.pending_read_buffer = Vec::new(); // empty the pending read buffer - if let Some(key) = remote_pubkey { + if let Some(key) = handshake.get_remote_pubkey() { remote_pubkey_option = Some(key); } - peer.pending_outbound_buffer.push_back(response); + if let Some(act) = next_act { + peer.pending_outbound_buffer.push_back(act.serialize()); + } + if let Some(conduit) = conduit { conduit_option = Some(conduit); } diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 1b415ffad34..d58134b033b 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -10,7 +10,7 @@ use secp256k1::{PublicKey, SecretKey}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; -use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH}; +use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, Act}; use ln::peers::handshake::hash::HandshakeHash; use ln::peers::handshake::states::{ActOneExpectation, ActThreeExpectation, ActTwoExpectation, HandshakeState}; @@ -24,6 +24,7 @@ mod tests; pub struct PeerHandshake { state: Option, private_key: SecretKey, + remote_public_key: Option, ephemeral_private_key: SecretKey, read_buffer: Vec, @@ -31,23 +32,38 @@ pub struct PeerHandshake { impl PeerHandshake { /// Instantiate a new handshake with a node identity secret key and an ephemeral private key - pub fn new(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { + pub fn new_outbound(private_key: &SecretKey, remote_public_key: &PublicKey, ephemeral_private_key: &SecretKey) -> Self { Self { state: Some(HandshakeState::Uninitiated), private_key: (*private_key).clone(), + remote_public_key: Some(remote_public_key.clone()), ephemeral_private_key: (*ephemeral_private_key).clone(), read_buffer: Vec::new(), } } - /// Make the handshake object inbound in anticipation of a peer's first handshake act - pub fn make_inbound(&mut self) { - let public_key = Self::private_key_to_public_key(&self.private_key); + /// Instantiate a new handshake in anticipation of a peer's first handshake act + pub fn new_inbound(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { + let mut handshake = Self { + state: Some(HandshakeState::Uninitiated), + private_key: (*private_key).clone(), + remote_public_key: None, + ephemeral_private_key: (*ephemeral_private_key).clone(), + read_buffer: Vec::new(), + }; + let public_key = Self::private_key_to_public_key(&private_key); let (hash, chaining_key) = Self::initialize_state(&public_key); - self.state = Some(HandshakeState::AwaitingActOne(ActOneExpectation { + handshake.state = Some(HandshakeState::AwaitingActOne(ActOneExpectation { hash, chaining_key, - })) + })); + handshake + } + + /// Getter accessor for the remote public key. It is useful for inbound connections to obtain + /// the remote peer's public key once it is extracted from the third act message. + pub fn get_remote_pubkey(&self) -> Option { + self.remote_public_key } fn initialize_state(public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { @@ -77,19 +93,18 @@ impl PeerHandshake { /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Conduit option if the handshake was just processed to completion and messages can now be encrypted and decrypted /// `.2`: Public key option if the handshake was inbound and the peer's static identity pubkey was just learned - pub fn process_act(&mut self, input: &[u8], remote_public_key: Option<&PublicKey>) -> Result<(Vec, Option, Option), String> { - let mut response: Vec = Vec::new(); + pub fn process_act(&mut self, input: &[u8]) -> Result<(Option, Option), String> { + let mut response = None; let mut connected_peer = None; - let mut remote_pubkey = None; self.read_buffer.extend_from_slice(input); let read_buffer_length = self.read_buffer.len(); match &self.state { &Some(HandshakeState::Uninitiated) => { - let remote_public_key = remote_public_key.ok_or("remote_public_key must be Some for outbound connections")?; + let remote_public_key = &self.remote_public_key.ok_or("outbound connections must be initialized with new_outbound")?; let act_one = self.initiate(&remote_public_key)?; - response = act_one.0.to_vec(); + response = Some(Act::One(act_one)); } &Some(HandshakeState::AwaitingActOne(_)) => { if read_buffer_length < ACT_ONE_LENGTH { @@ -101,7 +116,7 @@ impl PeerHandshake { self.read_buffer.drain(..ACT_ONE_LENGTH); let act_two = self.process_act_one(ActOne(act_one_buffer))?; - response = act_two.0.to_vec(); + response = Some(Act::Two(act_two)); } &Some(HandshakeState::AwaitingActTwo(_)) => { if read_buffer_length < ACT_TWO_LENGTH { @@ -119,7 +134,7 @@ impl PeerHandshake { self.read_buffer.drain(..); } - response = act_three.0.to_vec(); + response = Some(Act::Three(act_three)); connected_peer = Some(conduit); } &Some(HandshakeState::AwaitingActThree(_)) => { @@ -139,13 +154,13 @@ impl PeerHandshake { } connected_peer = Some(conduit); - remote_pubkey = Some(public_key); + self.remote_public_key = Some(public_key); } _ => { return Err("no acts left to process".to_string()); } }; - Ok((response, connected_peer, remote_pubkey)) + Ok((response, connected_peer)) } /// Initiate the handshake with a peer and return the first act diff --git a/lightning/src/ln/peers/handshake/tests.rs b/lightning/src/ln/peers/handshake/tests.rs index f0dcff6d993..4b0d2592777 100644 --- a/lightning/src/ln/peers/handshake/tests.rs +++ b/lightning/src/ln/peers/handshake/tests.rs @@ -17,11 +17,11 @@ fn test_exchange() { let local_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); let remote_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - let mut local_handshake = PeerHandshake::new(&local_private_key, &local_ephemeral_private_key); - let mut remote_handshake = PeerHandshake::new(&remote_private_key, &remote_ephemeral_private_key); - let remote_public_key = PublicKey::from_secret_key(&curve, &remote_private_key); + let mut local_handshake = PeerHandshake::new_outbound(&local_private_key, &remote_public_key, &local_ephemeral_private_key); + let mut remote_handshake = PeerHandshake::new_inbound(&remote_private_key, &remote_ephemeral_private_key); + let act_1 = local_handshake.initiate(&remote_public_key).unwrap(); let act_1_hex = hex::encode(&act_1.0.to_vec()); assert_eq!(act_1_hex, "00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a"); From 0fbd8953e5b3c17c4d73a2e9b784a5c1ad343588 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 27 Feb 2020 11:39:10 -0800 Subject: [PATCH 15/96] Panic when attempting invalid state transitions. --- lightning/src/ln/peer_handler.rs | 75 +++++++++++++------------ lightning/src/ln/peers/handshake/mod.rs | 19 +++---- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index c20503fed9c..8c2d9559686 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -341,8 +341,9 @@ impl PeerManager where ($msg: expr) => { { log_trace!(self, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - if let PeerState::Connected(ref mut conduit) = peer.encryptor { - peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!($msg)[..])); + match peer.encryptor { + PeerState::Connected(ref mut conduit) => peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!($msg)[..])), + _ => panic!("peer must be connected!") } } } @@ -597,22 +598,22 @@ impl PeerManager where wire::Message::Init(msg) => { if msg.features.requires_unknown_bits() { log_info!(self, "Peer global features required unknown version bits"); - return Err(PeerHandleError { no_connection_possible: true }); + return Err(PeerHandleError{ no_connection_possible: true }); } if msg.features.requires_unknown_bits() { log_info!(self, "Peer local features required unknown version bits"); - return Err(PeerHandleError { no_connection_possible: true }); + return Err(PeerHandleError{ no_connection_possible: true }); } if peer.their_features.is_some() { - return Err(PeerHandleError { no_connection_possible: false }); + return Err(PeerHandleError{ no_connection_possible: false }); } log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", - if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, - if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, - if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, - if msg.features.supports_unknown_bits() { "present" } else { "none" }, - if msg.features.supports_unknown_bits() { "present" } else { "none" }); + if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, + if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, + if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, + if msg.features.supports_unknown_bits() { "present" } else { "none" }, + if msg.features.supports_unknown_bits() { "present" } else { "none" }); if msg.features.initial_routing_sync() { peer.sync_status = InitSyncTracker::ChannelsSyncing(0); @@ -631,7 +632,7 @@ impl PeerManager where self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); peer.their_features = Some(msg.features); - } + }, wire::Message::Error(msg) => { let mut data_is_printable = true; for b in msg.data.bytes() { @@ -648,104 +649,104 @@ impl PeerManager where } self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); if msg.channel_id == [0; 32] { - return Err(PeerHandleError { no_connection_possible: true }); + return Err(PeerHandleError{ no_connection_possible: true }); } - } + }, wire::Message::Ping(msg) => { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; encode_and_send_msg!(resp); } - } + }, wire::Message::Pong(_msg) => { peer.awaiting_pong = false; - } + }, // Channel messages: wire::Message::OpenChannel(msg) => { self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - } + }, wire::Message::AcceptChannel(msg) => { self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - } + }, wire::Message::FundingCreated(msg) => { self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::FundingSigned(msg) => { self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::FundingLocked(msg) => { self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::Shutdown(msg) => { self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::ClosingSigned(msg) => { self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); - } + }, // Commitment messages: wire::Message::UpdateAddHTLC(msg) => { self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::UpdateFulfillHTLC(msg) => { self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::UpdateFailHTLC(msg) => { self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::UpdateFailMalformedHTLC(msg) => { self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::CommitmentSigned(msg) => { self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::RevokeAndACK(msg) => { self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::UpdateFee(msg) => { self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::ChannelReestablish(msg) => { self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); - } + }, // Routing messages: wire::Message::AnnouncementSignatures(msg) => { self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); - } + }, wire::Message::ChannelAnnouncement(msg) => { let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); if should_forward { // TODO: forward msg along to all our other peers! } - } + }, wire::Message::NodeAnnouncement(msg) => { let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); if should_forward { // TODO: forward msg along to all our other peers! } - } + }, wire::Message::ChannelUpdate(msg) => { let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); if should_forward { // TODO: forward msg along to all our other peers! } - } + }, // Unknown messages: wire::Message::Unknown(msg_type) if msg_type.is_even() => { // Fail the channel if message is an even, unknown type as per BOLT #1. - return Err(PeerHandleError { no_connection_possible: true }); - } - wire::Message::Unknown(_) => {} + return Err(PeerHandleError{ no_connection_possible: true }); + }, + wire::Message::Unknown(_) => {}, } } } diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index d58134b033b..c6d20496c57 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -60,8 +60,8 @@ impl PeerHandshake { handshake } - /// Getter accessor for the remote public key. It is useful for inbound connections to obtain - /// the remote peer's public key once it is extracted from the third act message. + /// Return the remote public key once it has been extracted from the third act. + /// Potentially useful for inbound connections pub fn get_remote_pubkey(&self) -> Option { self.remote_public_key } @@ -86,13 +86,11 @@ impl PeerHandshake { /// Process act dynamically /// # Arguments /// `input`: Byte slice received from peer as part of the handshake protocol - /// `remote_public_key`: If outbound, the peer's static identity public key needs is required for the handshake initiation /// /// # Return values /// Returns a tuple with the following components: /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Conduit option if the handshake was just processed to completion and messages can now be encrypted and decrypted - /// `.2`: Public key option if the handshake was inbound and the peer's static identity pubkey was just learned pub fn process_act(&mut self, input: &[u8]) -> Result<(Option, Option), String> { let mut response = None; let mut connected_peer = None; @@ -157,7 +155,7 @@ impl PeerHandshake { self.remote_public_key = Some(public_key); } _ => { - return Err("no acts left to process".to_string()); + panic!("no acts left to process"); } }; Ok((response, connected_peer)) @@ -195,7 +193,6 @@ impl PeerHandshake { let act_one_expectation = match state { Some(HandshakeState::AwaitingActOne(act_state)) => act_state, Some(HandshakeState::Uninitiated) => { - // this can also be initiated from a blank state let public_key = Self::private_key_to_public_key(&self.private_key); let (hash, chaining_key) = Self::initialize_state(&public_key); ActOneExpectation { @@ -205,7 +202,7 @@ impl PeerHandshake { } _ => { self.state = state; - return Err("unexpected state".to_string()); + panic!("unexpected state"); } }; @@ -244,7 +241,7 @@ impl PeerHandshake { Some(HandshakeState::AwaitingActTwo(act_state)) => act_state, _ => { self.state = state; - return Err("unexpected state".to_string()); + panic!("unexpected state".to_string()); } }; @@ -269,7 +266,7 @@ impl PeerHandshake { let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); - let mut act_three = [0u8; 66]; + let mut act_three = [0u8; ACT_THREE_LENGTH]; act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); act_three[50..].copy_from_slice(authentication_tag.as_slice()); @@ -292,12 +289,13 @@ impl PeerHandshake { Some(HandshakeState::AwaitingActThree(act_state)) => act_state, _ => { self.state = state; - return Err("unexpected state".to_string()); + panic!("unexpected state".to_string()); } }; let version = act.0[0]; if version != 0 { + // this should not crash the process, hence no panic return Err("unexpected version".to_string()); } @@ -356,6 +354,7 @@ impl PeerHandshake { fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { let version = act_bytes[0]; if version != 0 { + // this should not crash the process, hence no panic return Err("unexpected version".to_string()); } From 6f4e76a5c98dbcdf2f9ccaf5f458e967bd90c33c Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 12 Mar 2020 15:32:54 -0700 Subject: [PATCH 16/96] Group peer handler's connected state checks instead of repeating them in each iteration. --- lightning/src/ln/peer_handler.rs | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index fbd82eef537..79691942fef 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -901,32 +901,22 @@ impl PeerManager where let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { //TODO: Do whatever we're gonna do for handling dropped messages }); - for msg in update_add_htlcs { - if let PeerState::Connected(ref mut conduit) = peer.encryptor { + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + for msg in update_add_htlcs { peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); } - } - for msg in update_fulfill_htlcs { - if let PeerState::Connected(ref mut conduit) = peer.encryptor { + for msg in update_fulfill_htlcs { peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); } - } - for msg in update_fail_htlcs { - if let PeerState::Connected(ref mut conduit) = peer.encryptor { + for msg in update_fail_htlcs { peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); } - } - for msg in update_fail_malformed_htlcs { - if let PeerState::Connected(ref mut conduit) = peer.encryptor { + for msg in update_fail_malformed_htlcs { peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); } - } - if let &Some(ref msg) = update_fee { - if let PeerState::Connected(ref mut conduit) = peer.encryptor { + if let &Some(ref msg) = update_fee { peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(msg))); } - } - if let PeerState::Connected(ref mut conduit) = peer.encryptor { peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(commitment_signed))); } self.do_attempt_write_data(&mut descriptor, peer); @@ -1012,11 +1002,13 @@ impl PeerManager where let encoded_msg = encode_msg!(msg); for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.channel_encryptor.is_ready_for_encryption() || peer.their_features.is_none() || + if !peer.encryptor.is_ready_for_encryption() || peer.their_features.is_none() || !peer.should_forward_node_announcement(msg.contents.node_id) { continue } - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encoded_msg[..])); + if let PeerState::Connected(ref mut conduit) = peer.encryptor { + peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_msg[..])); + } self.do_attempt_write_data(&mut (*descriptor).clone(), peer); } } From c2227b640b0bf9f3c37b5fe5d4df2acd237c954e Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Fri, 13 Mar 2020 12:11:37 -0700 Subject: [PATCH 17/96] Fix missing init message send upon connection initiation. --- lightning/src/ln/peer_handler.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 79691942fef..2f256d29f3f 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -480,6 +480,8 @@ impl PeerManager where let mut conduit_option = None; let mut remote_pubkey_option = None; + let mut needs_to_send_init_message = false; + if let &mut PeerState::Authenticating(ref mut handshake) = &mut peer.encryptor { let (next_act, conduit) = handshake.process_act(&peer.pending_read_buffer).unwrap(); peer.pending_read_buffer = Vec::new(); // empty the pending read buffer @@ -488,11 +490,16 @@ impl PeerManager where remote_pubkey_option = Some(key); } + let mut has_remaining_act = false; if let Some(act) = next_act { + has_remaining_act = true; peer.pending_outbound_buffer.push_back(act.serialize()); } if let Some(conduit) = conduit { + if has_remaining_act { + needs_to_send_init_message = true; + } conduit_option = Some(conduit); } } @@ -557,6 +564,16 @@ impl PeerManager where } } + if needs_to_send_init_message { + let mut features = InitFeatures::supported(); + if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.set_initial_routing_sync(); + } + + let resp = msgs::Init { features }; + encode_and_send_msg!(resp); + } + let message_option = conduit.decrypt_single_message(Some(&peer.pending_read_buffer.clone())); peer.pending_read_buffer = Vec::new(); // empty the pending read buffer let msg_data = if let Some(message) = message_option { From 2df93cadbf9b82c6529e627cd4b61741469024af Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 9 Apr 2020 11:48:22 -0700 Subject: [PATCH 18/96] fix some unit tests --- lightning/src/ln/peer_handler.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 936b522c676..2b00b95c4ce 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -474,13 +474,15 @@ impl PeerManager where let pause_read = match peers.peers.get_mut(peer_descriptor) { None => panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => { + let mut read_from_conduit_buffer = false; peer.pending_read_buffer.extend_from_slice(&data); - while peer.pending_read_buffer.len() > 0 { + while peer.pending_read_buffer.len() > 0 || read_from_conduit_buffer { let mut conduit_option = None; let mut remote_pubkey_option = None; let mut needs_to_send_init_message = false; + read_from_conduit_buffer = false; if let &mut PeerState::Authenticating(ref mut handshake) = &mut peer.encryptor { let (next_act, conduit) = handshake.process_act(&peer.pending_read_buffer).unwrap(); @@ -577,6 +579,7 @@ impl PeerManager where let message_option = conduit.decrypt_single_message(Some(&peer.pending_read_buffer.clone())); peer.pending_read_buffer = Vec::new(); // empty the pending read buffer let msg_data = if let Some(message) = message_option { + read_from_conduit_buffer = true; message } else { break; From eda13bfc4b8ad97f431fbe6b21de7ee150b7a488 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 9 Apr 2020 13:31:12 -0700 Subject: [PATCH 19/96] Disconnect peer if act message is too short. --- lightning/src/ln/peer_handler.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs index 2b00b95c4ce..52ee18ed77a 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peer_handler.rs @@ -485,7 +485,13 @@ impl PeerManager where read_from_conduit_buffer = false; if let &mut PeerState::Authenticating(ref mut handshake) = &mut peer.encryptor { - let (next_act, conduit) = handshake.process_act(&peer.pending_read_buffer).unwrap(); + let (next_act, conduit) = match handshake.process_act(&peer.pending_read_buffer) { + Ok(act_result) => act_result, + Err(e) => { + log_trace!(self, "Invalid act message; disconnecting: {}", e); + return Err(PeerHandleError{ no_connection_possible: false }); + } + }; peer.pending_read_buffer = Vec::new(); // empty the pending read buffer if let Some(key) = handshake.get_remote_pubkey() { From 4e6b25a2e6d85d8d7fbe44b3c00adb0a6c97dfb0 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 9 Apr 2020 14:29:42 -0700 Subject: [PATCH 20/96] Replace unwrapping public keys with handleable errors in handshake module. --- lightning/src/ln/peers/handshake/mod.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index c6d20496c57..8ff3a32d21b 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -310,8 +310,11 @@ impl PeerHandshake { let remote_pubkey_vec = chacha::decrypt(&act_three_expectation.temporary_key, 1, &hash.value, &tagged_encrypted_pubkey)?; let mut remote_pubkey_bytes = [0u8; 33]; remote_pubkey_bytes.copy_from_slice(remote_pubkey_vec.as_slice()); - // todo: replace unwrap with handleable error type - let remote_pubkey = PublicKey::from_slice(&remote_pubkey_bytes).unwrap(); + let remote_pubkey = if let Ok(public_key) = PublicKey::from_slice(&remote_pubkey_bytes) { + public_key + } else { + return Err("invalid remote public key".to_string()); + }; hash.update(&tagged_encrypted_pubkey); @@ -360,8 +363,11 @@ impl PeerHandshake { let mut ephemeral_public_key_bytes = [0u8; 33]; ephemeral_public_key_bytes.copy_from_slice(&act_bytes[1..34]); - // todo: replace unwrap with handleable error type - let ephemeral_public_key = PublicKey::from_slice(&ephemeral_public_key_bytes).unwrap(); + let ephemeral_public_key = if let Ok(public_key) = PublicKey::from_slice(&ephemeral_public_key_bytes) { + public_key + } else { + return Err("invalid remote ephemeral public key".to_string()); + }; let mut chacha_tag = [0u8; 16]; chacha_tag.copy_from_slice(&act_bytes[34..50]); From 4deb2903a562faaf4a3e45a47a11610e674057f5 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 30 Apr 2020 03:26:45 -0700 Subject: [PATCH 21/96] Split conduit into encryptor and decryptor components (to allow for borrow splits). Extract handshake response method in peer handler into separate method. Create iterator pattern for decryptor. --- fuzz/src/full_stack.rs | 20 +- lightning-net-tokio/src/lib.rs | 4 +- lightning/src/ln/mod.rs | 1 - lightning/src/ln/peers/conduit.rs | 182 ++++++++---- .../ln/{peer_handler.rs => peers/handler.rs} | 260 +++++++++--------- lightning/src/ln/peers/handshake/mod.rs | 20 +- lightning/src/ln/peers/mod.rs | 1 + 7 files changed, 272 insertions(+), 216 deletions(-) rename lightning/src/ln/{peer_handler.rs => peers/handler.rs} (93%) diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 3ae4e56b5f1..12d1482f514 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -23,7 +23,7 @@ use lightning::chain::transaction::OutPoint; use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface}; use lightning::ln::channelmonitor; use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage}; -use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor}; +use lightning::ln::peers::handler::{MessageHandler,PeerManager,SocketDescriptor}; use lightning::ln::router::Router; use lightning::util::events::{EventsProvider,Event}; use lightning::util::enforcing_trait_impls::EnforcingChannelKeys; @@ -858,15 +858,15 @@ mod tests { super::do_test(&::hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000000300320003000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000030012000603000000000000000000000000000000030016001000000000030000000000000000000000000000000300120141030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000222ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030053030000000000000000000000000000000000000000000000000000000000000005030000000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000fd00fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d0000000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d000000000000000000000000000000000000000000000000000000000000000301000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001030132000300000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003014200030200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000300000000000000000000000000000003011200060100000000000000000000000000000003011600100000000001000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd00fd00fd0301120110010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e02000000000000001a00000000004c4b4000000000000003e800000000000003e80000000203f00005030000000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000200030000000000000000000000000000000000000000000000000000000000000300030000000000000000000000000000000000000000000000000000000000000400030000000000000000000000000000000000000000000000000000000000000500030000000000000000000000000000000301210000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233900000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000000000000000000000000000000b030112004301000000000000000000000000000000030153002439000000000000000000000000000000000000000000000000000000000000000301000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e8000000010000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000004d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a008239000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000000000000000000000000000301120063010000000000000000000000000000000301730085390000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e8000000010000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200630300000000000000000000000000000003007300853d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d00000000000000000000000000000000000000000000000000000000000000be00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833900000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000030112006301000000000000000000000000000000030173008539000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000305000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000004f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e0000010000000000000003e800000000010000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffef000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003060000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d0200000001390000000000000000000000000000000000000000000000000000000000000000000000000000008002000100000000000022002090000000000000000000000000000000000000000000000000000000000000006cc10000000000001600145c000000000000000000000000000000000000000500002000fd00fd0c005e0200000001fd00000000000000000000000000000000000000000000000000000000000000000000000000000000014f00000000000000220020f6000000000000000000000000000000000000000000000000000000000000000000000000fd0c000000fd0c00000c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc)); let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingSigned event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 2 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 3 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 4 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendRevokeAndACK event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&4)); // 5 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 6 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 1 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 8 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 1 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 9 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingSigned event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 2 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 3 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 4 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendRevokeAndACK event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&4)); // 5 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 6 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 1 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 8 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 1 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 9 assert_eq!(log_entries.get(&("lightning::ln::channelmonitor".to_string(), "Input spending remote commitment tx (00000000000000000000000000000000000000000000000000000000000000fd:0) in 0000000000000000000000000000000000000000000000000000000000000044 resolves outbound HTLC with payment hash ff00000000000000000000000000000000000000000000000000000000000000 with timeout".to_string())), Some(&1)); // 10 } } diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index dd0b861c197..a899aebb0ae 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -66,8 +66,8 @@ use tokio::{io, time}; use tokio::sync::mpsc; use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use lightning::ln::peer_handler; -use lightning::ln::peer_handler::SocketDescriptor as LnSocketTrait; +use lightning::ln::peers::handler; +use lightning::ln::peers::handler::SocketDescriptor as LnSocketTrait; use lightning::ln::msgs::ChannelMessageHandler; use std::{task, thread}; diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index fb312209d73..a7cc86e9b71 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -14,7 +14,6 @@ pub mod channelmonitor; pub mod msgs; pub mod router; pub mod peers; -pub mod peer_handler; pub mod chan_utils; pub mod features; pub(crate) mod onchaintx; diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 9d848f45b8f..dc17a91c15c 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -15,35 +15,120 @@ const KEY_ROTATION_INDEX: u32 = 1000; /// Automatically handles key rotation. /// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering. pub struct Conduit { - pub(crate) sending_key: SymmetricKey, - pub(crate) receiving_key: SymmetricKey, + pub(super) encryptor: Encryptor, + pub(super) decryptor: Decryptor - pub(crate) sending_chaining_key: SymmetricKey, - pub(crate) receiving_chaining_key: SymmetricKey, +} + +pub(super) struct Encryptor { + sending_key: SymmetricKey, + sending_chaining_key: SymmetricKey, + sending_nonce: u32, +} - pub(crate) receiving_nonce: u32, - pub(crate) sending_nonce: u32, +pub(super) struct Decryptor { + receiving_key: SymmetricKey, + receiving_chaining_key: SymmetricKey, + receiving_nonce: u32, - pub(super) read_buffer: Option>, + pending_message_length: Option, + read_buffer: Option>, +} + +impl Iterator for Decryptor { + type Item = Vec; + + fn next(&mut self) -> Option { + self.decrypt_single_message(None) + } } impl Conduit { + /// Instantiate a new Conduit with specified sending and receiving keys + pub fn new(sending_key: SymmetricKey, sending_chaining_key: SymmetricKey, receiving_key: SymmetricKey, receiving_chaining_key: SymmetricKey) -> Self { + Conduit { + encryptor: Encryptor { + sending_key, + sending_chaining_key, + sending_nonce: 0 + }, + decryptor: Decryptor { + receiving_key, + receiving_chaining_key, + receiving_nonce: 0, + read_buffer: None, + pending_message_length: None + } + } + } + /// Encrypt data to be sent to peer pub fn encrypt(&mut self, buffer: &[u8]) -> Vec { + self.encryptor.encrypt(buffer) + } + + pub(super) fn read(&mut self, data: &[u8]) { + self.decryptor.read(data) + } + + /// Decrypt a single message. If data containing more than one message has been received, + /// only the first message will be returned, and the rest stored in the internal buffer. + /// If a message pending in the buffer still hasn't been decrypted, that message will be + /// returned in lieu of anything new, even if new data is provided. + pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Option> { + self.decryptor.decrypt_single_message(new_data) + } + + /// Decrypt a message from the beginning of the provided buffer. Returns the consumed number of bytes. + fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { + self.decryptor.decrypt(buffer) + } + + fn increment_sending_nonce(&mut self) { + self.encryptor.increment_nonce() + } + + fn increment_receiving_nonce(&mut self) { + self.decryptor.increment_nonce() + } + + fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { + *nonce += 1; + if *nonce == KEY_ROTATION_INDEX { + Self::rotate_key(chaining_key, key); + *nonce = 0; + } + } + + fn rotate_key(chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { + let (new_chaining_key, new_key) = hkdf::derive(chaining_key, key); + chaining_key.copy_from_slice(&new_chaining_key); + key.copy_from_slice(&new_key); + } +} + +impl Encryptor { + pub(super) fn encrypt(&mut self, buffer: &[u8]) -> Vec { let length = buffer.len() as u16; let length_bytes = byte_utils::be16_to_array(length); let mut ciphertext = vec![0u8; TAGGED_MESSAGE_LENGTH_HEADER_SIZE + length as usize + chacha::TAG_SIZE]; ciphertext[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes)); - self.increment_sending_nonce(); + self.increment_nonce(); ciphertext[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer)); - self.increment_sending_nonce(); + self.increment_nonce(); ciphertext } + fn increment_nonce(&mut self) { + Conduit::increment_nonce(&mut self.sending_nonce, &mut self.sending_chaining_key, &mut self.sending_key); + } +} + +impl Decryptor { pub(super) fn read(&mut self, data: &[u8]) { let read_buffer = self.read_buffer.get_or_insert(Vec::new()); read_buffer.extend_from_slice(data); @@ -70,61 +155,53 @@ impl Conduit { current_message } - /// Decrypt a message from the beginning of the provided buffer. Returns the consumed number of bytes. fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { - if buffer.len() < TAGGED_MESSAGE_LENGTH_HEADER_SIZE { - // A message must be at least 18 bytes (2 for encrypted length, 16 for the tag) - return (None, 0); - } + let message_length = if let Some(length) = self.pending_message_length { + // we have already decrypted the header + length + } else { + if buffer.len() < TAGGED_MESSAGE_LENGTH_HEADER_SIZE { + // A message must be at least 18 bytes (2 for encrypted length, 16 for the tag) + return (None, 0); + } + + let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; + let mut length_bytes = [0u8; MESSAGE_LENGTH_HEADER_SIZE]; + length_bytes.copy_from_slice(&chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap()); - let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; - let mut length_bytes = [0u8; MESSAGE_LENGTH_HEADER_SIZE]; - length_bytes.copy_from_slice(&chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap()); - // message_length is the length of the encrypted message excluding its trailing 16-byte tag - let message_length = byte_utils::slice_to_be16(&length_bytes) as usize; + self.increment_nonce(); + + // the message length + byte_utils::slice_to_be16(&length_bytes) as usize + }; let message_end_index = TAGGED_MESSAGE_LENGTH_HEADER_SIZE + message_length + chacha::TAG_SIZE; + if buffer.len() < message_end_index { + self.pending_message_length = Some(message_length); return (None, 0); } - let encrypted_message = &buffer[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..message_end_index]; + self.pending_message_length = None; - self.increment_receiving_nonce(); + let encrypted_message = &buffer[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..message_end_index]; let message = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_message).unwrap(); - self.increment_receiving_nonce(); + self.increment_nonce(); (Some(message), message_end_index) } - fn increment_sending_nonce(&mut self) { - Self::increment_nonce(&mut self.sending_nonce, &mut self.sending_chaining_key, &mut self.sending_key); - } - - fn increment_receiving_nonce(&mut self) { - Self::increment_nonce(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); - } - - fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { - *nonce += 1; - if *nonce == KEY_ROTATION_INDEX { - Self::rotate_key(chaining_key, key); - *nonce = 0; - } - } - - fn rotate_key(chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { - let (new_chaining_key, new_key) = hkdf::derive(chaining_key, key); - chaining_key.copy_from_slice(&new_chaining_key); - key.copy_from_slice(&new_key); + fn increment_nonce(&mut self) { + Conduit::increment_nonce(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); } } #[cfg(test)] mod tests { use hex; + use ln::peers::conduit::Conduit; fn setup_peers() -> (Conduit, Conduit) { @@ -140,25 +217,8 @@ mod tests { let mut receiving_key = [0u8; 32]; receiving_key.copy_from_slice(&receiving_key_vec); - let connected_peer = Conduit { - sending_key, - receiving_key, - sending_chaining_key: chaining_key, - receiving_chaining_key: chaining_key, - sending_nonce: 0, - receiving_nonce: 0, - read_buffer: None, - }; - - let remote_peer = Conduit { - sending_key: receiving_key, - receiving_key: sending_key, - sending_chaining_key: chaining_key, - receiving_chaining_key: chaining_key, - sending_nonce: 0, - receiving_nonce: 0, - read_buffer: None, - }; + let connected_peer = Conduit::new(sending_key, chaining_key, receiving_key, chaining_key); + let remote_peer = Conduit::new(receiving_key, chaining_key, sending_key, chaining_key); (connected_peer, remote_peer) } diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peers/handler.rs similarity index 93% rename from lightning/src/ln/peer_handler.rs rename to lightning/src/ln/peers/handler.rs index be7ea68aa62..6096fd2f4ca 100644 --- a/lightning/src/ln/peer_handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -114,6 +114,12 @@ enum PeerState { Connected(Conduit), } +enum PeerDataProcessingDecision { + CompleteHandshake(bool, Option), + Continue, + Disconnect(PeerHandleError) +} + impl PeerState { fn is_ready_for_encryption(&self) -> bool { match self { @@ -121,6 +127,35 @@ impl PeerState { _ => false } } + + fn process_peer_data(&mut self, data: &[u8], mutable_response_buffer: &mut LinkedList>) -> PeerDataProcessingDecision { + if let &mut PeerState::Authenticating(ref mut handshake) = self { + let (next_act, conduit) = match handshake.process_act(data) { + Ok(act_result) => act_result, + Err(e) => { + return PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false }); + } + }; + + let requires_response = next_act.is_some(); + if let Some(act) = next_act { + mutable_response_buffer.push_back(act.serialize()); + } + + let remote_pubkey_option = handshake.get_remote_pubkey(); + if let Some(conduit) = conduit { + *self = PeerState::Connected(conduit); + return PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey_option) + } + + }; + + if let &mut PeerState::Connected(ref mut conduit) = self { + conduit.read(data); + } + + PeerDataProcessingDecision::Continue + } } struct Peer { @@ -478,122 +513,99 @@ impl PeerManager where let pause_read = match peers.peers.get_mut(peer_descriptor) { None => panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => { - let mut read_from_conduit_buffer = false; - peer.pending_read_buffer.extend_from_slice(&data); - while peer.pending_read_buffer.len() > 0 || read_from_conduit_buffer { - - let mut conduit_option = None; - let mut remote_pubkey_option = None; - - let mut needs_to_send_init_message = false; - read_from_conduit_buffer = false; - - if let &mut PeerState::Authenticating(ref mut handshake) = &mut peer.encryptor { - let (next_act, conduit) = match handshake.process_act(&peer.pending_read_buffer) { - Ok(act_result) => act_result, - Err(e) => { - log_trace!(self, "Invalid act message; disconnecting: {}", e); - return Err(PeerHandleError{ no_connection_possible: false }); - } - }; - peer.pending_read_buffer = Vec::new(); // empty the pending read buffer + let mut send_init_message = false; + let data_processing_decision = peer.encryptor.process_peer_data(data, &mut peer.pending_outbound_buffer); - if let Some(key) = handshake.get_remote_pubkey() { - remote_pubkey_option = Some(key); - } - - let mut has_remaining_act = false; - if let Some(act) = next_act { - has_remaining_act = true; - peer.pending_outbound_buffer.push_back(act.serialize()); - } - - if let Some(conduit) = conduit { - if has_remaining_act { - needs_to_send_init_message = true; - } - conduit_option = Some(conduit); - } + let conduit_option = match data_processing_decision { + PeerDataProcessingDecision::Disconnect(e) => { + log_trace!(self, "Invalid act message; disconnecting: {}", e); + return Err(e); } - if let Some(key) = remote_pubkey_option { - peer.their_node_id = Some(key); - } + PeerDataProcessingDecision::CompleteHandshake(needs_to_send_init_message, remote_pubkey_option) => { + send_init_message = needs_to_send_init_message; - if let Some(conduit) = conduit_option { - // Rust 1.22 does not allow assignment in a borrowed context, even if mutable - peer.encryptor = PeerState::Connected(conduit); + if let Some(key) = remote_pubkey_option { + peer.their_node_id = Some(key); + } - // the handshake has finished, so one way or another, we now have their node id match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { hash_map::Entry::Occupied(_) => { log_trace!(self, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); peer.their_node_id = None; // Unset so that we don't generate a peer_disconnected event - return Err(PeerHandleError{ no_connection_possible: false }) - }, + return Err(PeerHandleError { no_connection_possible: false }); + } hash_map::Entry::Vacant(entry) => { log_trace!(self, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); entry.insert(peer_descriptor.clone()) - }, + } }; + + None + } + PeerDataProcessingDecision::Continue => { + if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { + Some(conduit) + } else { + None + } } + }; - if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { - macro_rules! encode_and_send_msg { - ($msg: expr) => { - { - log_trace!(self, "Encoding and sending message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - // we are in a context where conduit is known - peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!(&$msg)[..])); - peers.peers_needing_send.insert(peer_descriptor.clone()); - } + if let Some(conduit) = conduit_option { + + let encryptor = &mut conduit.encryptor; + let decryptor = &mut conduit.decryptor; + + macro_rules! encode_and_send_msg { + ($msg: expr) => { + { + log_trace!(self, "Encoding and sending message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + // we are in a context where conduit is known + peer.pending_outbound_buffer.push_back(encryptor.encrypt(&encode_msg!(&$msg)[..])); + peers.peers_needing_send.insert(peer_descriptor.clone()); } } + } - macro_rules! try_potential_handleerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(e) => { - match e.action { - msgs::ErrorAction::DisconnectPeer { msg: _ } => { - //TODO: Try to push msg - log_trace!(self, "Got Err handling message, disconnecting peer because {}", e.err); - return Err(PeerHandleError{ no_connection_possible: false }); - }, - msgs::ErrorAction::IgnoreError => { - log_trace!(self, "Got Err handling message, ignoring because {}", e.err); - continue; - }, - msgs::ErrorAction::SendErrorMessage { msg } => { - log_trace!(self, "Got Err handling message, sending Error message because {}", e.err); - encode_and_send_msg!(msg); - continue; - }, - } + macro_rules! try_potential_handleerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(e) => { + match e.action { + msgs::ErrorAction::DisconnectPeer { msg: _ } => { + //TODO: Try to push msg + log_trace!(self, "Got Err handling message, disconnecting peer because {}", e.err); + return Err(PeerHandleError{ no_connection_possible: false }); + }, + msgs::ErrorAction::IgnoreError => { + log_trace!(self, "Got Err handling message, ignoring because {}", e.err); + continue; + }, + msgs::ErrorAction::SendErrorMessage { msg } => { + log_trace!(self, "Got Err handling message, sending Error message because {}", e.err); + encode_and_send_msg!(msg); + continue; + }, } - }; - } + } + }; } + } - if needs_to_send_init_message { - let mut features = InitFeatures::supported(); - if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.set_initial_routing_sync(); - } - - let resp = msgs::Init { features }; - encode_and_send_msg!(resp); + if send_init_message { + let mut features = InitFeatures::supported(); + if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.set_initial_routing_sync(); } - let message_option = conduit.decrypt_single_message(Some(&peer.pending_read_buffer.clone())); - peer.pending_read_buffer = Vec::new(); // empty the pending read buffer - let msg_data = if let Some(message) = message_option { - read_from_conduit_buffer = true; - message - } else { - break; - }; + let resp = msgs::Init { features }; + encode_and_send_msg!(resp); + send_init_message = false + } + + for msg_data in decryptor { { { @@ -636,14 +648,14 @@ impl PeerManager where wire::Message::Init(msg) => { if msg.features.requires_unknown_bits() { log_info!(self, "Peer global features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }); + return Err(PeerHandleError { no_connection_possible: true }); } if msg.features.requires_unknown_bits() { log_info!(self, "Peer local features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }); + return Err(PeerHandleError { no_connection_possible: true }); } if peer.their_features.is_some() { - return Err(PeerHandleError{ no_connection_possible: false }); + return Err(PeerHandleError { no_connection_possible: false }); } log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", @@ -670,7 +682,7 @@ impl PeerManager where self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); peer.their_features = Some(msg.features); - }, + } wire::Message::Error(msg) => { let mut data_is_printable = true; for b in msg.data.bytes() { @@ -687,107 +699,107 @@ impl PeerManager where } self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); if msg.channel_id == [0; 32] { - return Err(PeerHandleError{ no_connection_possible: true }); + return Err(PeerHandleError { no_connection_possible: true }); } - }, + } wire::Message::Ping(msg) => { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; encode_and_send_msg!(resp); } - }, + } wire::Message::Pong(_msg) => { peer.awaiting_pong = false; - }, + } // Channel messages: wire::Message::OpenChannel(msg) => { self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - }, + } wire::Message::AcceptChannel(msg) => { self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - }, + } wire::Message::FundingCreated(msg) => { self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::FundingSigned(msg) => { self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::FundingLocked(msg) => { self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::Shutdown(msg) => { self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::ClosingSigned(msg) => { self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); - }, + } // Commitment messages: wire::Message::UpdateAddHTLC(msg) => { self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::UpdateFulfillHTLC(msg) => { self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::UpdateFailHTLC(msg) => { self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::UpdateFailMalformedHTLC(msg) => { self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::CommitmentSigned(msg) => { self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::RevokeAndACK(msg) => { self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::UpdateFee(msg) => { self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::ChannelReestablish(msg) => { self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); - }, + } // Routing messages: wire::Message::AnnouncementSignatures(msg) => { self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); - }, + } wire::Message::ChannelAnnouncement(msg) => { let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); if should_forward { // TODO: forward msg along to all our other peers! } - }, + } wire::Message::NodeAnnouncement(msg) => { let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); if should_forward { // TODO: forward msg along to all our other peers! } - }, + } wire::Message::ChannelUpdate(msg) => { let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); if should_forward { // TODO: forward msg along to all our other peers! } - }, + } // Unknown messages: wire::Message::Unknown(msg_type) if msg_type.is_even() => { log_debug!(self, "Received unknown even message of type {}, disconnecting peer!", msg_type); // Fail the channel if message is an even, unknown type as per BOLT #1. - return Err(PeerHandleError{ no_connection_possible: true }); - }, + return Err(PeerHandleError { no_connection_possible: true }); + } wire::Message::Unknown(msg_type) => { log_trace!(self, "Received unknown odd message of type {}, ignoring", msg_type); - }, + } } } } @@ -1208,7 +1220,7 @@ mod tests { use bitcoin::BitcoinHash; use bitcoin::network::constants::Network; use bitcoin::blockdata::constants::genesis_block; - use ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor}; + use ln::peers::handler::{PeerManager, MessageHandler, SocketDescriptor}; use ln::msgs; use ln::features::ChannelFeatures; use util::events; diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 8ff3a32d21b..6f73c266c33 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -270,15 +270,7 @@ impl PeerHandshake { act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); act_three[50..].copy_from_slice(authentication_tag.as_slice()); - let connected_peer = Conduit { - sending_key, - receiving_key, - sending_chaining_key: chaining_key, - receiving_chaining_key: chaining_key, - sending_nonce: 0, - receiving_nonce: 0, - read_buffer: None, - }; + let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key, chaining_key); Ok((ActThree(act_three), connected_peer)) } @@ -323,15 +315,7 @@ impl PeerHandshake { let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); - let connected_peer = Conduit { - sending_key, - receiving_key, - sending_chaining_key: chaining_key, - receiving_chaining_key: chaining_key, - sending_nonce: 0, - receiving_nonce: 0, - read_buffer: None, - }; + let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key, chaining_key); Ok((remote_pubkey, connected_peer)) } diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index 23807e840d3..f8082c50f10 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -6,4 +6,5 @@ mod chacha; pub mod conduit; pub mod handshake; +pub mod handler; mod hkdf; From 5e9c3507f2e569f3ae157aa89fa8debb774d53a9 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 30 Apr 2020 04:02:23 -0700 Subject: [PATCH 22/96] Fix conduit constructor bugs and revert indentation for message processing block. --- lightning/src/ln/peers/conduit.rs | 10 +- lightning/src/ln/peers/handler.rs | 402 ++++++++++++------------ lightning/src/ln/peers/handshake/mod.rs | 4 +- 3 files changed, 206 insertions(+), 210 deletions(-) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index dc17a91c15c..74e420b192a 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -45,16 +45,16 @@ impl Iterator for Decryptor { impl Conduit { /// Instantiate a new Conduit with specified sending and receiving keys - pub fn new(sending_key: SymmetricKey, sending_chaining_key: SymmetricKey, receiving_key: SymmetricKey, receiving_chaining_key: SymmetricKey) -> Self { + pub fn new(sending_key: SymmetricKey, receiving_key: SymmetricKey, chaining_key: SymmetricKey) -> Self { Conduit { encryptor: Encryptor { sending_key, - sending_chaining_key, + sending_chaining_key: chaining_key, sending_nonce: 0 }, decryptor: Decryptor { receiving_key, - receiving_chaining_key, + receiving_chaining_key: chaining_key, receiving_nonce: 0, read_buffer: None, pending_message_length: None @@ -217,8 +217,8 @@ mod tests { let mut receiving_key = [0u8; 32]; receiving_key.copy_from_slice(&receiving_key_vec); - let connected_peer = Conduit::new(sending_key, chaining_key, receiving_key, chaining_key); - let remote_peer = Conduit::new(receiving_key, chaining_key, sending_key, chaining_key); + let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key); + let remote_peer = Conduit::new(receiving_key, sending_key, chaining_key); (connected_peer, remote_peer) } diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 6096fd2f4ca..cdf01c5663b 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -129,31 +129,32 @@ impl PeerState { } fn process_peer_data(&mut self, data: &[u8], mutable_response_buffer: &mut LinkedList>) -> PeerDataProcessingDecision { - if let &mut PeerState::Authenticating(ref mut handshake) = self { - let (next_act, conduit) = match handshake.process_act(data) { - Ok(act_result) => act_result, - Err(e) => { - return PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false }); + match self { + &mut PeerState::Authenticating(ref mut handshake) => { + let (next_act, conduit) = match handshake.process_act(data) { + Ok(act_result) => act_result, + Err(e) => { + return PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false }); + } + }; + + let requires_response = next_act.is_some(); + if let Some(act) = next_act { + mutable_response_buffer.push_back(act.serialize()); } - }; - let requires_response = next_act.is_some(); - if let Some(act) = next_act { - mutable_response_buffer.push_back(act.serialize()); + let remote_pubkey_option = handshake.get_remote_pubkey(); + if let Some(conduit) = conduit { + *self = PeerState::Connected(conduit); + return PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey_option); + } } - let remote_pubkey_option = handshake.get_remote_pubkey(); - if let Some(conduit) = conduit { - *self = PeerState::Connected(conduit); - return PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey_option) + &mut PeerState::Connected(ref mut conduit) => { + conduit.read(data); } - }; - if let &mut PeerState::Connected(ref mut conduit) = self { - conduit.read(data); - } - PeerDataProcessingDecision::Continue } } @@ -513,10 +514,12 @@ impl PeerManager where let pause_read = match peers.peers.get_mut(peer_descriptor) { None => panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => { + let mut send_init_message = false; - let data_processing_decision = peer.encryptor.process_peer_data(data, &mut peer.pending_outbound_buffer); + let mut conduit_option = None; - let conduit_option = match data_processing_decision { + let data_processing_decision = peer.encryptor.process_peer_data(data, &mut peer.pending_outbound_buffer); + match data_processing_decision { PeerDataProcessingDecision::Disconnect(e) => { log_trace!(self, "Invalid act message; disconnecting: {}", e); return Err(e); @@ -541,13 +544,13 @@ impl PeerManager where } }; - None + if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { + conduit_option = Some(conduit); + } } PeerDataProcessingDecision::Continue => { if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { - Some(conduit) - } else { - None + conduit_option = Some(conduit); } } }; @@ -606,203 +609,196 @@ impl PeerManager where } for msg_data in decryptor { + let mut reader = ::std::io::Cursor::new(&msg_data[..]); + let message_result = wire::read(&mut reader); + let message = match message_result { + Ok(x) => x, + Err(e) => { + match e { + msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::UnknownRequiredFeature => { + log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + continue; + } + msgs::DecodeError::InvalidValue => { + log_debug!(self, "Got an invalid value while deserializing message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ShortRead => { + log_debug!(self, "Deserialization failed due to shortness of message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), + } + } + }; - { - { - { - let mut reader = ::std::io::Cursor::new(&msg_data[..]); - let message_result = wire::read(&mut reader); - let message = match message_result { - Ok(x) => x, - Err(e) => { - match e { - msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to update!"); - continue; - } - msgs::DecodeError::InvalidValue => { - log_debug!(self, "Got an invalid value while deserializing message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ShortRead => { - log_debug!(self, "Deserialization failed due to shortness of message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), - } - } - }; + log_trace!(self, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - log_trace!(self, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + // Need an Init as first message + if let wire::Message::Init(_) = message {} else if peer.their_features.is_none() { + log_trace!(self, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); + return Err(PeerHandleError { no_connection_possible: false }); + } - // Need an Init as first message - if let wire::Message::Init(_) = message {} else if peer.their_features.is_none() { - log_trace!(self, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); - return Err(PeerHandleError { no_connection_possible: false }); + match message { + // Setup and Control messages: + wire::Message::Init(msg) => { + if msg.features.requires_unknown_bits() { + log_info!(self, "Peer global features required unknown version bits"); + return Err(PeerHandleError { no_connection_possible: true }); + } + if msg.features.requires_unknown_bits() { + log_info!(self, "Peer local features required unknown version bits"); + return Err(PeerHandleError { no_connection_possible: true }); + } + if peer.their_features.is_some() { + return Err(PeerHandleError { no_connection_possible: false }); + } + + log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", + if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, + if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, + if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, + if msg.features.supports_unknown_bits() { "present" } else { "none" }, + if msg.features.supports_unknown_bits() { "present" } else { "none" }); + + if msg.features.initial_routing_sync() { + peer.sync_status = InitSyncTracker::ChannelsSyncing(0); + peers.peers_needing_send.insert(peer_descriptor.clone()); + } + + if !peer.outbound { + let mut features = InitFeatures::supported(); + if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.set_initial_routing_sync(); } - match message { - // Setup and Control messages: - wire::Message::Init(msg) => { - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer global features required unknown version bits"); - return Err(PeerHandleError { no_connection_possible: true }); - } - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer local features required unknown version bits"); - return Err(PeerHandleError { no_connection_possible: true }); - } - if peer.their_features.is_some() { - return Err(PeerHandleError { no_connection_possible: false }); - } - - log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", - if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, - if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, - if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, - if msg.features.supports_unknown_bits() { "present" } else { "none" }, - if msg.features.supports_unknown_bits() { "present" } else { "none" }); - - if msg.features.initial_routing_sync() { - peer.sync_status = InitSyncTracker::ChannelsSyncing(0); - peers.peers_needing_send.insert(peer_descriptor.clone()); - } - - if !peer.outbound { - let mut features = InitFeatures::supported(); - if self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.set_initial_routing_sync(); - } - - let resp = msgs::Init { features }; - encode_and_send_msg!(resp); - } - - self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); - peer.their_features = Some(msg.features); - } - wire::Message::Error(msg) => { - let mut data_is_printable = true; - for b in msg.data.bytes() { - if b < 32 || b > 126 { - data_is_printable = false; - break; - } - } - - if data_is_printable { - log_debug!(self, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); - } else { - log_debug!(self, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); - } - self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); - if msg.channel_id == [0; 32] { - return Err(PeerHandleError { no_connection_possible: true }); - } - } + let resp = msgs::Init { features }; + encode_and_send_msg!(resp); + } - wire::Message::Ping(msg) => { - if msg.ponglen < 65532 { - let resp = msgs::Pong { byteslen: msg.ponglen }; - encode_and_send_msg!(resp); - } - } - wire::Message::Pong(_msg) => { - peer.awaiting_pong = false; - } + self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); + peer.their_features = Some(msg.features); + } + wire::Message::Error(msg) => { + let mut data_is_printable = true; + for b in msg.data.bytes() { + if b < 32 || b > 126 { + data_is_printable = false; + break; + } + } - // Channel messages: - wire::Message::OpenChannel(msg) => { - self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - } - wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - } + if data_is_printable { + log_debug!(self, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); + } else { + log_debug!(self, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); + } + self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); + if msg.channel_id == [0; 32] { + return Err(PeerHandleError { no_connection_possible: true }); + } + } - wire::Message::FundingCreated(msg) => { - self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::FundingSigned(msg) => { - self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::FundingLocked(msg) => { - self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); - } + wire::Message::Ping(msg) => { + if msg.ponglen < 65532 { + let resp = msgs::Pong { byteslen: msg.ponglen }; + encode_and_send_msg!(resp); + } + } + wire::Message::Pong(_msg) => { + peer.awaiting_pong = false; + } - wire::Message::Shutdown(msg) => { - self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::ClosingSigned(msg) => { - self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); - } + // Channel messages: + wire::Message::OpenChannel(msg) => { + self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + } + wire::Message::AcceptChannel(msg) => { + self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + } - // Commitment messages: - wire::Message::UpdateAddHTLC(msg) => { - self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFulfillHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFailHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFailMalformedHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); - } + wire::Message::FundingCreated(msg) => { + self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::FundingSigned(msg) => { + self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::FundingLocked(msg) => { + self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); + } - wire::Message::CommitmentSigned(msg) => { - self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::RevokeAndACK(msg) => { - self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFee(msg) => { - self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::ChannelReestablish(msg) => { - self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); - } + wire::Message::Shutdown(msg) => { + self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::ClosingSigned(msg) => { + self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); + } - // Routing messages: - wire::Message::AnnouncementSignatures(msg) => { - self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::ChannelAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); + // Commitment messages: + wire::Message::UpdateAddHTLC(msg) => { + self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFulfillHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFailHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFailMalformedHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); + } - if should_forward { - // TODO: forward msg along to all our other peers! - } - } - wire::Message::NodeAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); + wire::Message::CommitmentSigned(msg) => { + self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::RevokeAndACK(msg) => { + self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::UpdateFee(msg) => { + self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::ChannelReestablish(msg) => { + self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); + } - if should_forward { - // TODO: forward msg along to all our other peers! - } - } - wire::Message::ChannelUpdate(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); + // Routing messages: + wire::Message::AnnouncementSignatures(msg) => { + self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); + } + wire::Message::ChannelAnnouncement(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); - if should_forward { - // TODO: forward msg along to all our other peers! - } - } + if should_forward { + // TODO: forward msg along to all our other peers! + } + } + wire::Message::NodeAnnouncement(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); - // Unknown messages: - wire::Message::Unknown(msg_type) if msg_type.is_even() => { - log_debug!(self, "Received unknown even message of type {}, disconnecting peer!", msg_type); - // Fail the channel if message is an even, unknown type as per BOLT #1. - return Err(PeerHandleError { no_connection_possible: true }); - } - wire::Message::Unknown(msg_type) => { - log_trace!(self, "Received unknown odd message of type {}, ignoring", msg_type); - } - } + if should_forward { + // TODO: forward msg along to all our other peers! } } + wire::Message::ChannelUpdate(msg) => { + let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); + + if should_forward { + // TODO: forward msg along to all our other peers! + } + } + + // Unknown messages: + wire::Message::Unknown(msg_type) if msg_type.is_even() => { + log_debug!(self, "Received unknown even message of type {}, disconnecting peer!", msg_type); + // Fail the channel if message is an even, unknown type as per BOLT #1. + return Err(PeerHandleError { no_connection_possible: true }); + } + wire::Message::Unknown(msg_type) => { + log_trace!(self, "Received unknown odd message of type {}, ignoring", msg_type); + } } } diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 6f73c266c33..235d75ea4c6 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -270,7 +270,7 @@ impl PeerHandshake { act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); act_three[50..].copy_from_slice(authentication_tag.as_slice()); - let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key, chaining_key); + let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key); Ok((ActThree(act_three), connected_peer)) } @@ -315,7 +315,7 @@ impl PeerHandshake { let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); - let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key, chaining_key); + let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key); Ok((remote_pubkey, connected_peer)) } From 029bb66b7f42cc9b34bc59f5e9189c0afab4481c Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 30 Apr 2020 11:14:55 -0700 Subject: [PATCH 23/96] Replace hashing and secp256k1 dependencies with components of the bitcoin crate. --- fuzz/src/full_stack.rs | 18 +++++++++--------- lightning/src/ln/peers/handshake/hash.rs | 6 +++--- lightning/src/ln/peers/handshake/mod.rs | 10 +++++----- lightning/src/ln/peers/handshake/states.rs | 4 ++-- lightning/src/ln/peers/handshake/tests.rs | 6 +++--- lightning/src/ln/peers/hkdf.rs | 6 +++--- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index 6679b291001..274ac2829d9 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -881,15 +881,15 @@ mod tests { super::do_test(&::hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000000300320003000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000030012000603000000000000000000000000000000030016001000000000030000000000000000000000000000000300120141030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000222ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030053030000000000000000000000000000000000000000000000000000000000000005030000000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000fd00fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d0000000000000000000000000000000000000000000000000000000000000000005c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d000000000000000000000000000000000000000000000000000000000000000301000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000001030132000300000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003014200030200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000300000000000000000000000000000003011200060100000000000000000000000000000003011600100000000001000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd00fd00fd0301120110010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e02000000000000001a00000000004c4b4000000000000003e800000000000003e80000000203f00005030000000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000200030000000000000000000000000000000000000000000000000000000000000300030000000000000000000000000000000000000000000000000000000000000400030000000000000000000000000000000000000000000000000000000000000500030000000000000000000000000000000301210000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233900000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000000000000000000000000000000b030112004301000000000000000000000000000000030153002439000000000000000000000000000000000000000000000000000000000000000301000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e80000007b0000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000004d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a008239000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000000000000000000000000000301120063010000000000000000000000000000000301730085390000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e80000007b0000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200630300000000000000000000000000000003007300853d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d00000000000000000000000000000000000000000000000000000000000000be00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833900000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000030112006301000000000000000000000000000000030173008539000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000305000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000004f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e0000010000000000000003e8000000007b0000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200a4030000000000000000000000000000000300b400843d00000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003060000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013900000000000000000000000000000000000000000000000000000000000000000000000000000080020001000000000000220020bb000000000000000000000000000000000000000000000000000000000000006cc10000000000001600145c000000000000000000000000000000000000000500002000fd00fd0c005e0200000001d600000000000000000000000000000000000000000000000000000000000000000000000000000000014f00000000000000220020f600000000000000000000000000000000000000000000000000000000000000000000000c00000c000000fd0c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc)); let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingSigned event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 2 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 3 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 4 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendRevokeAndACK event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&4)); // 5 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 6 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 1 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 8 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 1 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 9 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingSigned event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 2 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 3 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 4 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendRevokeAndACK event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&4)); // 5 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 6 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 1 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 8 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 1 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 9 assert_eq!(log_entries.get(&("lightning::ln::channelmonitor".to_string(), "Input spending remote commitment tx (00000000000000000000000000000000000000000000000000000000000000d6:0) in 000000000000000000000000000000000000000000000000000000000000006f resolves outbound HTLC with payment hash ff00000000000000000000000000000000000000000000000000000000000000 with timeout".to_string())), Some(&1)); // 10 } } diff --git a/lightning/src/ln/peers/handshake/hash.rs b/lightning/src/ln/peers/handshake/hash.rs index 0beef40fd93..e7704b37e34 100644 --- a/lightning/src/ln/peers/handshake/hash.rs +++ b/lightning/src/ln/peers/handshake/hash.rs @@ -1,5 +1,5 @@ -use bitcoin_hashes::{Hash, HashEngine}; -use bitcoin_hashes::sha256::Hash as Sha256; +use bitcoin::hashes::{Hash, HashEngine}; +use bitcoin::hashes::sha256::Hash as Sha256; pub(crate) struct HandshakeHash { pub(super) value: [u8; 32] @@ -22,4 +22,4 @@ impl HandshakeHash { sha.input(input); self.value = Sha256::from_engine(sha).into_inner(); } -} \ No newline at end of file +} diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 235d75ea4c6..32efc969a22 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -2,11 +2,11 @@ //! Handshake states can be advanced automatically, or by manually calling the appropriate step. //! Once complete, returns an instance of Conduit. -use secp256k1; +use bitcoin::secp256k1; -use bitcoin_hashes::{Hash, HashEngine}; -use bitcoin_hashes::sha256::Hash as Sha256; -use secp256k1::{PublicKey, SecretKey}; +use bitcoin::hashes::{Hash, HashEngine}; +use bitcoin::hashes::sha256::Hash as Sha256; +use bitcoin::secp256k1::{PublicKey, SecretKey}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; @@ -391,4 +391,4 @@ impl PeerHandshake { sha.input(preimage.as_ref()); Sha256::from_engine(sha).into_inner() } -} \ No newline at end of file +} diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 643d7b16f9a..2a7401f5e9b 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -1,5 +1,5 @@ use ln::peers::handshake::hash::HandshakeHash; -use secp256k1::{SecretKey, PublicKey}; +use bitcoin::secp256k1::{SecretKey, PublicKey}; pub enum HandshakeState { Uninitiated, @@ -27,4 +27,4 @@ pub struct ActThreeExpectation { pub(super) temporary_key: [u8; 32], pub(super) ephemeral_private_key: SecretKey, pub(super) remote_ephemeral_public_key: PublicKey, -} \ No newline at end of file +} diff --git a/lightning/src/ln/peers/handshake/tests.rs b/lightning/src/ln/peers/handshake/tests.rs index 4b0d2592777..e99500d1399 100644 --- a/lightning/src/ln/peers/handshake/tests.rs +++ b/lightning/src/ln/peers/handshake/tests.rs @@ -1,9 +1,9 @@ #![cfg(test)] use hex; -use secp256k1; +use bitcoin::secp256k1; -use secp256k1::key::{PublicKey, SecretKey}; +use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use ln::peers::handshake::PeerHandshake; @@ -36,4 +36,4 @@ fn test_exchange() { assert_eq!(act_3_hex, "00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"); remote_handshake.process_act_three(act_3).unwrap(); -} \ No newline at end of file +} diff --git a/lightning/src/ln/peers/hkdf.rs b/lightning/src/ln/peers/hkdf.rs index 396515a4bf2..48415594114 100644 --- a/lightning/src/ln/peers/hkdf.rs +++ b/lightning/src/ln/peers/hkdf.rs @@ -1,5 +1,5 @@ -use bitcoin_hashes::{Hash, HashEngine, Hmac, HmacEngine}; -use bitcoin_hashes::sha256::Hash as Sha256; +use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine}; +use bitcoin::hashes::sha256::Hash as Sha256; pub fn derive(salt: &[u8], master: &[u8]) -> ([u8; 32], [u8; 32]) { let mut hmac = HmacEngine::::new(salt); @@ -15,4 +15,4 @@ pub fn derive(salt: &[u8], master: &[u8]) -> ([u8; 32], [u8; 32]) { hmac.input(&[2; 1]); // sha256(prk | t1 | 2) = sha256(sha256(master) | sha256(sha256(sha256(master) | 1) | 2) (t1, Hmac::from_engine(hmac).into_inner()) -} \ No newline at end of file +} From 54b7464024448119447f96d06c7bc667cf2c05d7 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 30 Apr 2020 12:05:14 -0700 Subject: [PATCH 24/96] Restrict conduit borrow scope for compatibility with Rust 1.22.0. --- lightning/src/ln/peers/handler.rs | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index a6d2d856f45..7059bbd430e 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -129,6 +129,9 @@ impl PeerState { } fn process_peer_data(&mut self, data: &[u8], mutable_response_buffer: &mut LinkedList>) -> PeerDataProcessingDecision { + let mut conduit_option = None; + let mut decision_option = None; + match self { &mut PeerState::Authenticating(ref mut handshake) => { let (next_act, conduit) = match handshake.process_act(data) { @@ -145,8 +148,8 @@ impl PeerState { let remote_pubkey_option = handshake.get_remote_pubkey(); if let Some(conduit) = conduit { - *self = PeerState::Connected(conduit); - return PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey_option); + conduit_option = Some(conduit); + decision_option = Some(PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey_option)); } } @@ -155,6 +158,11 @@ impl PeerState { } }; + if let (Some(conduit), Some(decision)) = (conduit_option, decision_option) { + *self = PeerState::Connected(conduit); + return decision; + } + PeerDataProcessingDecision::Continue } } @@ -169,8 +177,6 @@ struct Peer { pending_outbound_buffer_first_msg_offset: usize, awaiting_write_event: bool, - pending_read_buffer: Vec, - sync_status: InitSyncTracker, awaiting_pong: bool, @@ -338,8 +344,6 @@ impl PeerManager where pending_outbound_buffer_first_msg_offset: 0, awaiting_write_event: false, - pending_read_buffer: Vec::new(), - sync_status: InitSyncTracker::NoSyncRequested, awaiting_pong: false, @@ -372,8 +376,6 @@ impl PeerManager where pending_outbound_buffer_first_msg_offset: 0, awaiting_write_event: false, - pending_read_buffer: Vec::new(), - sync_status: InitSyncTracker::NoSyncRequested, awaiting_pong: false, @@ -516,7 +518,6 @@ impl PeerManager where Some(peer) => { let mut send_init_message = false; - let mut conduit_option = None; let data_processing_decision = peer.encryptor.process_peer_data(data, &mut peer.pending_outbound_buffer); match data_processing_decision { @@ -543,19 +544,11 @@ impl PeerManager where entry.insert(peer_descriptor.clone()) } }; - - if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { - conduit_option = Some(conduit); - } - } - PeerDataProcessingDecision::Continue => { - if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { - conduit_option = Some(conduit); - } } + _ => {} }; - if let Some(conduit) = conduit_option { + if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { let encryptor = &mut conduit.encryptor; let decryptor = &mut conduit.decryptor; From fe705a90d04b03560a80b097227e0c7cdbe2ca45 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Thu, 30 Apr 2020 12:17:46 -0700 Subject: [PATCH 25/96] Fix lightning-net-tokio peer handler import. --- lightning-net-tokio/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index 9845f0dd2d2..6a2c78b17d3 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -26,7 +26,7 @@ //! type FeeEstimator = dyn lightning::chain::chaininterface::FeeEstimator; //! type ChannelMonitor = lightning::ln::channelmonitor::SimpleManyChannelMonitor, Arc>; //! type ChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager; -//! type PeerManager = lightning::ln::peer_handler::SimpleArcPeerManager; +//! type PeerManager = lightning::ln::peers::handler::SimpleArcPeerManager; //! //! // Connect to node with pubkey their_node_id at addr: //! async fn connect_to_node(peer_manager: PeerManager, channel_monitor: Arc, channel_manager: ChannelManager, their_node_id: PublicKey, addr: SocketAddr) { @@ -66,7 +66,7 @@ use tokio::{io, time}; use tokio::sync::mpsc; use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use lightning::ln::peers::handler; +use lightning::ln::peers::handler as peer_handler; use lightning::ln::peers::handler::SocketDescriptor as LnSocketTrait; use lightning::ln::msgs::ChannelMessageHandler; @@ -479,7 +479,7 @@ impl Hash for SocketDescriptor { mod tests { use lightning::ln::features::*; use lightning::ln::msgs::*; - use lightning::ln::peer_handler::{MessageHandler, PeerManager}; + use lightning::ln::peers::handler::{MessageHandler, PeerManager}; use lightning::util::events::*; use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey}; From be5e2a5b1523ada8c0357e57402d3c528080d2a3 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Fri, 12 Jun 2020 10:52:35 -0700 Subject: [PATCH 26/96] Apply message handling extraction to relocated peer handler. --- lightning/src/ln/peers/handler.rs | 629 ++++++++++++++---------------- 1 file changed, 294 insertions(+), 335 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 7059bbd430e..49c1adbe3e3 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -3,21 +3,23 @@ //! Instead of actually servicing sockets ourselves we require that you implement the //! SocketDescriptor interface and use that to receive actions which you should perform on the //! socket, and call into PeerManager with bytes read from the socket. The PeerManager will then -//! call into the provided message handlers (probably a ChannelManager and Router) with messages +//! call into the provided message handlers (probably a ChannelManager and NetGraphmsgHandler) with messages //! they should handle, and encoding/sending response messages. use bitcoin::secp256k1::key::{SecretKey,PublicKey}; use ln::features::InitFeatures; use ln::msgs; -use ln::msgs::ChannelMessageHandler; +use ln::msgs::{ChannelMessageHandler, LightningError, RoutingMessageHandler}; use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; -use util::ser::VecWriter; +use util::ser::{VecWriter, Writeable}; +use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; use ln::wire; use ln::wire::Encode; use util::byte_utils; use util::events::{MessageSendEvent, MessageSendEventsProvider}; use util::logger::Logger; +use routing::network_graph::NetGraphMsgHandler; use std::collections::{HashMap,hash_map,HashSet,LinkedList}; use std::sync::{Arc, Mutex}; @@ -33,13 +35,15 @@ use ln::peers::conduit::Conduit; use ln::peers::handshake::acts::Act; /// Provides references to trait impls which handle different types of messages. -pub struct MessageHandler where CM::Target: msgs::ChannelMessageHandler { +pub struct MessageHandler where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler { /// A message handler which handles messages specific to channels. Usually this is just a /// ChannelManager object. pub chan_handler: CM, /// A message handler which handles messages updating our knowledge of the network channel - /// graph. Usually this is just a Router object. - pub route_handler: Arc, + /// graph. Usually this is just a NetGraphMsgHandlerMonitor object. + pub route_handler: RM, } /// Provides an object which can be used to send data to and which uniquely identifies a connection @@ -85,7 +89,7 @@ pub trait SocketDescriptor : cmp::Eq + hash::Hash + Clone { pub struct PeerHandleError { /// Used to indicate that we probably can't make any future connections to this peer, implying /// we should go ahead and force-close any channels we have with it. - no_connection_possible: bool, + pub no_connection_possible: bool, } impl fmt::Debug for PeerHandleError { fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { @@ -227,7 +231,7 @@ fn _check_usize_is_32_or_64() { /// lifetimes). Other times you can afford a reference, which is more efficient, in which case /// SimpleRefPeerManager is the more appropriate type. Defining these type aliases prevents /// issues such as overly long function definitions. -pub type SimpleArcPeerManager = Arc>>; +pub type SimpleArcPeerManager = Arc, Arc, Arc>>, Arc>>; /// SimpleRefPeerManager is a type alias for a PeerManager reference, and is the reference /// counterpart to the SimpleArcPeerManager type alias. Use this type by default when you don't @@ -235,7 +239,7 @@ pub type SimpleArcPeerManager = Arc = PeerManager>; +pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, SD, M, T, F, C, L> = PeerManager, &'e NetGraphMsgHandler<&'g C, &'f L>, &'f L>; /// A PeerManager manages a set of peers, described by their SocketDescriptor and marshalls socket /// events into messages which it passes on to its MessageHandlers. @@ -245,8 +249,11 @@ pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, SD, M, T, F> = PeerManager where CM::Target: msgs::ChannelMessageHandler { - message_handler: MessageHandler, +pub struct PeerManager where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler, + L::Target: Logger { + message_handler: MessageHandler, peers: Mutex>, our_node_secret: SecretKey, ephemeral_key_midstate: Sha256Engine, @@ -256,7 +263,24 @@ pub struct PeerManager where CM::Target peer_counter_low: AtomicUsize, peer_counter_high: AtomicUsize, - logger: Arc, + logger: L, +} + +enum MessageHandlingError { + PeerHandleError(PeerHandleError), + LightningError(LightningError), +} + +impl From for MessageHandlingError { + fn from(error: PeerHandleError) -> Self { + MessageHandlingError::PeerHandleError(error) + } +} + +impl From for MessageHandlingError { + fn from(error: LightningError) -> Self { + MessageHandlingError::LightningError(error) + } } macro_rules! encode_msg { @@ -269,22 +293,25 @@ macro_rules! encode_msg { /// Manages and reacts to connection events. You probably want to use file descriptors as PeerIds. /// PeerIds may repeat, but only after socket_disconnected() has been called. -impl PeerManager where CM::Target: msgs::ChannelMessageHandler { +impl PeerManager where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler, + L::Target: Logger { /// Constructs a new PeerManager with the given message handlers and node_id secret key /// ephemeral_random_data is used to derive per-connection ephemeral keys and must be /// cryptographically secure random bytes. - pub fn new(message_handler: MessageHandler, our_node_secret: SecretKey, ephemeral_random_data: &[u8; 32], logger: Arc) -> PeerManager { + pub fn new(message_handler: MessageHandler, our_node_secret: SecretKey, ephemeral_random_data: &[u8; 32], logger: L) -> Self { let mut ephemeral_key_midstate = Sha256::engine(); ephemeral_key_midstate.input(ephemeral_random_data); PeerManager { - message_handler: message_handler, + message_handler, peers: Mutex::new(PeerHolder { peers: HashMap::new(), peers_needing_send: HashSet::new(), node_id_to_descriptor: HashMap::new() }), - our_node_secret: our_node_secret, + our_node_secret, ephemeral_key_midstate, peer_counter_low: AtomicUsize::new(0), peer_counter_high: AtomicUsize::new(0), @@ -389,7 +416,7 @@ impl PeerManager where macro_rules! encode_and_send_msg { ($msg: expr) => { { - log_trace!(self, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + log_trace!(self.logger, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); match peer.encryptor { PeerState::Connected(ref mut conduit) => peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!($msg)[..])), _ => panic!("peer must be connected!") @@ -509,6 +536,20 @@ impl PeerManager where } } + /// Append a message to a peer's pending outbound/write buffer, and update the map of peers needing sends accordingly. + fn enqueue_message(&self, peers_needing_send: &mut HashSet, peer: &mut Peer, descriptor: Descriptor, message: &M) { + let mut buffer = VecWriter(Vec::new()); + wire::write(message, &mut buffer).unwrap(); // crash if the write failed + let encoded_message = buffer.0; + + log_trace!(self.logger, "Enqueueing message of type {} to {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + match peer.encryptor { + PeerState::Connected(ref mut conduit) => peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!($msg)[..])), + _ => panic!("peer must be connected!") + } + peers_needing_send.insert(descriptor); + } + fn do_read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8]) -> Result { let pause_read = { let mut peers_lock = self.peers.lock().unwrap(); @@ -533,6 +574,7 @@ impl PeerManager where peer.their_node_id = Some(key); } + // insert node id match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { hash_map::Entry::Occupied(_) => { log_trace!(self, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); @@ -581,7 +623,7 @@ impl PeerManager where }, msgs::ErrorAction::SendErrorMessage { msg } => { log_trace!(self, "Got Err handling message, sending Error message because {}", e.err); - encode_and_send_msg!(msg); + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &msg); continue; }, } @@ -597,7 +639,7 @@ impl PeerManager where } let resp = msgs::Init { features }; - encode_and_send_msg!(resp); + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); send_init_message = false } @@ -610,15 +652,15 @@ impl PeerManager where match e { msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(self, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + log_debug!(self.logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); continue; } msgs::DecodeError::InvalidValue => { - log_debug!(self, "Got an invalid value while deserializing message"); + log_debug!(self.logger, "Got an invalid value while deserializing message"); return Err(PeerHandleError { no_connection_possible: false }); } msgs::DecodeError::ShortRead => { - log_debug!(self, "Deserialization failed due to shortness of message"); + log_debug!(self.logger, "Deserialization failed due to shortness of message"); return Err(PeerHandleError { no_connection_possible: false }); } msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), @@ -627,186 +669,215 @@ impl PeerManager where } }; - log_trace!(self, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - - // Need an Init as first message - if let wire::Message::Init(_) = message {} else if peer.their_features.is_none() { - log_trace!(self, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); - return Err(PeerHandleError { no_connection_possible: false }); + if let Err(handling_error) = self.handle_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), message){ + match handling_error { + MessageHandlingError::PeerHandleError(e) => { return Err(e) }, + MessageHandlingError::LightningError(e) => { + try_potential_handleerror!(Err(e)); + }, + } } + } - match message { - // Setup and Control messages: - wire::Message::Init(msg) => { - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer global features required unknown version bits"); - return Err(PeerHandleError { no_connection_possible: true }); - } - if msg.features.requires_unknown_bits() { - log_info!(self, "Peer local features required unknown version bits"); - return Err(PeerHandleError { no_connection_possible: true }); - } - if peer.their_features.is_some() { - return Err(PeerHandleError { no_connection_possible: false }); - } - - log_info!(self, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, unkown local flags: {}, unknown global flags: {}", - if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, - if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, - if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, - if msg.features.supports_unknown_bits() { "present" } else { "none" }, - if msg.features.supports_unknown_bits() { "present" } else { "none" }); - - if msg.features.initial_routing_sync() { - peer.sync_status = InitSyncTracker::ChannelsSyncing(0); - peers.peers_needing_send.insert(peer_descriptor.clone()); - } - - if !peer.outbound { - let mut features = InitFeatures::known(); - if !self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.clear_initial_routing_sync(); - } - - let resp = msgs::Init { features }; - encode_and_send_msg!(resp); - } - - self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); - peer.their_features = Some(msg.features); - } - wire::Message::Error(msg) => { - let mut data_is_printable = true; - for b in msg.data.bytes() { - if b < 32 || b > 126 { - data_is_printable = false; - break; - } - } + } - if data_is_printable { - log_debug!(self, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); - } else { - log_debug!(self, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); - } - self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); - if msg.channel_id == [0; 32] { - return Err(PeerHandleError { no_connection_possible: true }); - } - } + self.do_attempt_write_data(peer_descriptor, peer); - wire::Message::Ping(msg) => { - if msg.ponglen < 65532 { - let resp = msgs::Pong { byteslen: msg.ponglen }; - encode_and_send_msg!(resp); - } - } - wire::Message::Pong(_msg) => { - peer.awaiting_pong = false; - } + peer.pending_outbound_buffer.len() > 10 // pause_read + } + }; - // Channel messages: - wire::Message::OpenChannel(msg) => { - self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - } - wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); - } + pause_read + }; - wire::Message::FundingCreated(msg) => { - self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::FundingSigned(msg) => { - self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::FundingLocked(msg) => { - self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); - } + Ok(pause_read) + } - wire::Message::Shutdown(msg) => { - self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::ClosingSigned(msg) => { - self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); - } + /// Process an incoming message and return a decision (ok, lightning error, peer handling error) regarding the next action with the peer + fn handle_message(&self, peers_needing_send: &mut HashSet, peer: &mut Peer, peer_descriptor: Descriptor, message: wire::Message) -> Result<(), MessageHandlingError> { + log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - // Commitment messages: - wire::Message::UpdateAddHTLC(msg) => { - self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFulfillHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFailHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFailMalformedHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); - } + // Need an Init as first message + if let wire::Message::Init(_) = message { + } else if peer.their_features.is_none() { + log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); + return Err(PeerHandleError{ no_connection_possible: false }.into()); + } - wire::Message::CommitmentSigned(msg) => { - self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::RevokeAndACK(msg) => { - self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::UpdateFee(msg) => { - self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::ChannelReestablish(msg) => { - self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); - } + match message { + // Setup and Control messages: + wire::Message::Init(msg) => { + if msg.features.requires_unknown_bits() { + log_info!(self.logger, "Peer global features required unknown version bits"); + return Err(PeerHandleError{ no_connection_possible: true }.into()); + } + if msg.features.requires_unknown_bits() { + log_info!(self.logger, "Peer local features required unknown version bits"); + return Err(PeerHandleError{ no_connection_possible: true }.into()); + } + if peer.their_features.is_some() { + return Err(PeerHandleError{ no_connection_possible: false }.into()); + } - // Routing messages: - wire::Message::AnnouncementSignatures(msg) => { - self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); - } - wire::Message::ChannelAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_announcement(&msg)); + log_info!( + self.logger, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, static_remote_key: {}, unknown flags (local and global): {}", + if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, + if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, + if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, + if msg.features.supports_static_remote_key() { "supported" } else { "not supported"}, + if msg.features.supports_unknown_bits() { "present" } else { "none" } + ); + + if msg.features.initial_routing_sync() { + peer.sync_status = InitSyncTracker::ChannelsSyncing(0); + peers_needing_send.insert(peer_descriptor.clone()); + } + if !msg.features.supports_static_remote_key() { + log_debug!(self.logger, "Peer {} does not support static remote key, disconnecting with no_connection_possible", log_pubkey!(peer.their_node_id.unwrap())); + return Err(PeerHandleError{ no_connection_possible: true }.into()); + } - if should_forward { - // TODO: forward msg along to all our other peers! - } - } - wire::Message::NodeAnnouncement(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_node_announcement(&msg)); + if !peer.outbound { + let mut features = InitFeatures::known(); + if !self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.clear_initial_routing_sync(); + } - if should_forward { - // TODO: forward msg along to all our other peers! - } - } - wire::Message::ChannelUpdate(msg) => { - let should_forward = try_potential_handleerror!(self.message_handler.route_handler.handle_channel_update(&msg)); + let resp = msgs::Init { features }; + self.enqueue_message(peers_needing_send, peer, peer_descriptor.clone(), &resp); + } - if should_forward { - // TODO: forward msg along to all our other peers! - } - } + self.message_handler.chan_handler.peer_connected(&peer.their_node_id.unwrap(), &msg); + peer.their_features = Some(msg.features); + }, + wire::Message::Error(msg) => { + let mut data_is_printable = true; + for b in msg.data.bytes() { + if b < 32 || b > 126 { + data_is_printable = false; + break; + } + } - // Unknown messages: - wire::Message::Unknown(msg_type) if msg_type.is_even() => { - log_debug!(self, "Received unknown even message of type {}, disconnecting peer!", msg_type); - // Fail the channel if message is an even, unknown type as per BOLT #1. - return Err(PeerHandleError { no_connection_possible: true }); - } - wire::Message::Unknown(msg_type) => { - log_trace!(self, "Received unknown odd message of type {}, ignoring", msg_type); - } - } - } + if data_is_printable { + log_debug!(self.logger, "Got Err message from {}: {}", log_pubkey!(peer.their_node_id.unwrap()), msg.data); + } else { + log_debug!(self.logger, "Got Err message from {} with non-ASCII error message", log_pubkey!(peer.their_node_id.unwrap())); + } + self.message_handler.chan_handler.handle_error(&peer.their_node_id.unwrap(), &msg); + if msg.channel_id == [0; 32] { + return Err(PeerHandleError{ no_connection_possible: true }.into()); + } + }, - } + wire::Message::Ping(msg) => { + if msg.ponglen < 65532 { + let resp = msgs::Pong { byteslen: msg.ponglen }; + self.enqueue_message(peers_needing_send, peer, peer_descriptor.clone(), &resp); + } + }, + wire::Message::Pong(_msg) => { + peer.awaiting_pong = false; + }, + + // Channel messages: + wire::Message::OpenChannel(msg) => { + self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + }, + wire::Message::AcceptChannel(msg) => { + self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + }, + + wire::Message::FundingCreated(msg) => { + self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::FundingSigned(msg) => { + self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::FundingLocked(msg) => { + self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); + }, + + wire::Message::Shutdown(msg) => { + self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::ClosingSigned(msg) => { + self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); + }, + + // Commitment messages: + wire::Message::UpdateAddHTLC(msg) => { + self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFulfillHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFailHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFailMalformedHTLC(msg) => { + self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); + }, + + wire::Message::CommitmentSigned(msg) => { + self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::RevokeAndACK(msg) => { + self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::UpdateFee(msg) => { + self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::ChannelReestablish(msg) => { + self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); + }, + + // Routing messages: + wire::Message::AnnouncementSignatures(msg) => { + self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); + }, + wire::Message::ChannelAnnouncement(msg) => { + let should_forward = match self.message_handler.route_handler.handle_channel_announcement(&msg) { + Ok(v) => v, + Err(e) => { return Err(e.into()); }, + }; - self.do_attempt_write_data(peer_descriptor, peer); + if should_forward { + // TODO: forward msg along to all our other peers! + } + }, + wire::Message::NodeAnnouncement(msg) => { + let should_forward = match self.message_handler.route_handler.handle_node_announcement(&msg) { + Ok(v) => v, + Err(e) => { return Err(e.into()); }, + }; - peer.pending_outbound_buffer.len() > 10 // pause_read + if should_forward { + // TODO: forward msg along to all our other peers! } - }; + }, + wire::Message::ChannelUpdate(msg) => { + let should_forward = match self.message_handler.route_handler.handle_channel_update(&msg) { + Ok(v) => v, + Err(e) => { return Err(e.into()); }, + }; - pause_read + if should_forward { + // TODO: forward msg along to all our other peers! + } + }, + + // Unknown messages: + wire::Message::Unknown(msg_type) if msg_type.is_even() => { + log_debug!(self.logger, "Received unknown even message of type {}, disconnecting peer!", msg_type); + // Fail the channel if message is an even, unknown type as per BOLT #1. + return Err(PeerHandleError{ no_connection_possible: true }.into()); + }, + wire::Message::Unknown(msg_type) => { + log_trace!(self.logger, "Received unknown odd message of type {}, ignoring", msg_type); + } }; - - Ok(pause_read) + Ok(()) } /// Checks for any events generated by our handlers and processes them. Includes sending most @@ -1205,16 +1276,10 @@ impl PeerManager where #[cfg(test)] mod tests { - use bitcoin::secp256k1::Signature; - use bitcoin::BitcoinHash; - use bitcoin::network::constants::Network; - use bitcoin::blockdata::constants::genesis_block; - use ln::peers::handler::{PeerManager, MessageHandler, SocketDescriptor}; + use ln::peer_handler::{PeerManager, MessageHandler, SocketDescriptor}; use ln::msgs; - use ln::features::ChannelFeatures; use util::events; use util::test_utils; - use util::logger::Logger; use bitcoin::secp256k1::Secp256k1; use bitcoin::secp256k1::key::{SecretKey, PublicKey}; @@ -1222,9 +1287,8 @@ mod tests { use rand::{thread_rng, Rng}; use std; - use std::cmp::min; use std::sync::{Arc, Mutex}; - use std::sync::atomic::{AtomicUsize, Ordering}; + use std::sync::atomic::Ordering; #[derive(Clone)] struct FileDescriptor { @@ -1252,41 +1316,48 @@ mod tests { fn disconnect_socket(&mut self) {} } - fn create_chan_handlers(peer_count: usize) -> Vec { - let mut chan_handlers = Vec::new(); + struct PeerManagerCfg { + chan_handler: test_utils::TestChannelMessageHandler, + routing_handler: test_utils::TestRoutingMessageHandler, + logger: test_utils::TestLogger, + } + + fn create_peermgr_cfgs(peer_count: usize) -> Vec { + let mut cfgs = Vec::new(); for _ in 0..peer_count { - let chan_handler = test_utils::TestChannelMessageHandler::new(); - chan_handlers.push(chan_handler); + cfgs.push( + PeerManagerCfg{ + chan_handler: test_utils::TestChannelMessageHandler::new(), + logger: test_utils::TestLogger::new(), + routing_handler: test_utils::TestRoutingMessageHandler::new(), + } + ); } - chan_handlers + cfgs } - fn create_network<'a>(peer_count: usize, chan_handlers: &'a Vec, routing_handlers: Option<&'a Vec>>) -> Vec> { + fn create_network<'a>(peer_count: usize, cfgs: &'a Vec) -> Vec> { let mut peers = Vec::new(); let mut rng = thread_rng(); - let logger : Arc = Arc::new(test_utils::TestLogger::new()); let mut ephemeral_bytes = [0; 32]; rng.fill_bytes(&mut ephemeral_bytes); for i in 0..peer_count { - let router = if let Some(routers) = routing_handlers { routers[i].clone() } else { - Arc::new(test_utils::TestRoutingMessageHandler::new()) - }; let node_id = { let mut key_slice = [0;32]; rng.fill_bytes(&mut key_slice); SecretKey::from_slice(&key_slice).unwrap() }; - let msg_handler = MessageHandler { chan_handler: &chan_handlers[i], route_handler: router }; - let peer = PeerManager::new(msg_handler, node_id, &ephemeral_bytes, Arc::clone(&logger)); + let msg_handler = MessageHandler { chan_handler: &cfgs[i].chan_handler, route_handler: &cfgs[i].routing_handler }; + let peer = PeerManager::new(msg_handler, node_id, &ephemeral_bytes, &cfgs[i].logger); peers.push(peer); } peers } - fn establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { + fn establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { let secp_ctx = Secp256k1::new(); let a_id = PublicKey::from_secret_key(&secp_ctx, &peer_a.our_node_secret); let mut fd_a = FileDescriptor { fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())) }; @@ -1299,7 +1370,7 @@ mod tests { (fd_a.clone(), fd_b.clone()) } - fn establish_connection_and_read_events<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { + fn establish_connection_and_read_events<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { let (mut fd_a, mut fd_b) = establish_connection(peer_a, peer_b); assert_eq!(peer_b.read_event(&mut fd_b, &fd_a.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); assert_eq!(peer_a.read_event(&mut fd_a, &fd_b.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); @@ -1310,9 +1381,9 @@ mod tests { fn test_disconnect_peer() { // Simple test which builds a network of PeerManager, connects and brings them to NoiseState::Finished and // push a DisconnectPeer event to remove the node flagged by id - let chan_handlers = create_chan_handlers(2); + let cfgs = create_peermgr_cfgs(2); let chan_handler = test_utils::TestChannelMessageHandler::new(); - let mut peers = create_network(2, &chan_handlers, None); + let mut peers = create_network(2, &cfgs); establish_connection(&peers[0], &peers[1]); assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 1); @@ -1333,8 +1404,8 @@ mod tests { #[test] fn test_timer_tick_occurred() { // Create peers, a vector of two peer managers, perform initial set up and check that peers[0] has one Peer. - let chan_handlers = create_chan_handlers(2); - let peers = create_network(2, &chan_handlers, None); + let cfgs = create_peermgr_cfgs(2); + let peers = create_network(2, &cfgs); establish_connection(&peers[0], &peers[1]); assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 1); @@ -1347,119 +1418,13 @@ mod tests { assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 0); } - pub struct TestRoutingMessageHandler { - pub chan_upds_recvd: AtomicUsize, - pub chan_anns_recvd: AtomicUsize, - pub chan_anns_sent: AtomicUsize, - } - - impl TestRoutingMessageHandler { - pub fn new() -> Self { - TestRoutingMessageHandler { - chan_upds_recvd: AtomicUsize::new(0), - chan_anns_recvd: AtomicUsize::new(0), - chan_anns_sent: AtomicUsize::new(0), - } - } - - } - impl msgs::RoutingMessageHandler for TestRoutingMessageHandler { - fn handle_node_announcement(&self, _msg: &msgs::NodeAnnouncement) -> Result { - Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) - } - fn handle_channel_announcement(&self, _msg: &msgs::ChannelAnnouncement) -> Result { - self.chan_anns_recvd.fetch_add(1, Ordering::AcqRel); - Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) - } - fn handle_channel_update(&self, _msg: &msgs::ChannelUpdate) -> Result { - self.chan_upds_recvd.fetch_add(1, Ordering::AcqRel); - Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }) - } - fn handle_htlc_fail_channel_update(&self, _update: &msgs::HTLCFailChannelUpdate) {} - fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(msgs::ChannelAnnouncement, Option, Option)> { - let mut chan_anns = Vec::new(); - const TOTAL_UPDS: u64 = 100; - let end: u64 = min(starting_point + batch_amount as u64, TOTAL_UPDS - self.chan_anns_sent.load(Ordering::Acquire) as u64); - for i in starting_point..end { - let chan_upd_1 = get_dummy_channel_update(i); - let chan_upd_2 = get_dummy_channel_update(i); - let chan_ann = get_dummy_channel_announcement(i); - - chan_anns.push((chan_ann, Some(chan_upd_1), Some(chan_upd_2))); - } - - self.chan_anns_sent.fetch_add(chan_anns.len(), Ordering::AcqRel); - chan_anns - } - - fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec { - Vec::new() - } - - fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool { - true - } - } - - fn get_dummy_channel_announcement(short_chan_id: u64) -> msgs::ChannelAnnouncement { - use bitcoin::secp256k1::ffi::Signature as FFISignature; - let secp_ctx = Secp256k1::new(); - let network = Network::Testnet; - let node_1_privkey = SecretKey::from_slice(&[42; 32]).unwrap(); - let node_2_privkey = SecretKey::from_slice(&[41; 32]).unwrap(); - let node_1_btckey = SecretKey::from_slice(&[40; 32]).unwrap(); - let node_2_btckey = SecretKey::from_slice(&[39; 32]).unwrap(); - let unsigned_ann = msgs::UnsignedChannelAnnouncement { - features: ChannelFeatures::known(), - chain_hash: genesis_block(network).header.bitcoin_hash(), - short_channel_id: short_chan_id, - node_id_1: PublicKey::from_secret_key(&secp_ctx, &node_1_privkey), - node_id_2: PublicKey::from_secret_key(&secp_ctx, &node_2_privkey), - bitcoin_key_1: PublicKey::from_secret_key(&secp_ctx, &node_1_btckey), - bitcoin_key_2: PublicKey::from_secret_key(&secp_ctx, &node_2_btckey), - excess_data: Vec::new(), - }; - - msgs::ChannelAnnouncement { - node_signature_1: Signature::from(FFISignature::new()), - node_signature_2: Signature::from(FFISignature::new()), - bitcoin_signature_1: Signature::from(FFISignature::new()), - bitcoin_signature_2: Signature::from(FFISignature::new()), - contents: unsigned_ann, - } - } - - fn get_dummy_channel_update(short_chan_id: u64) -> msgs::ChannelUpdate { - use bitcoin::secp256k1::ffi::Signature as FFISignature; - let network = Network::Testnet; - msgs::ChannelUpdate { - signature: Signature::from(FFISignature::new()), - contents: msgs::UnsignedChannelUpdate { - chain_hash: genesis_block(network).header.bitcoin_hash(), - short_channel_id: short_chan_id, - timestamp: 0, - flags: 0, - cltv_expiry_delta: 0, - htlc_minimum_msat: 0, - fee_base_msat: 0, - fee_proportional_millionths: 0, - excess_data: vec![], - } - } - } - #[test] fn test_do_attempt_write_data() { // Create 2 peers with custom TestRoutingMessageHandlers and connect them. - let chan_handlers = create_chan_handlers(2); - let mut routing_handlers: Vec> = Vec::new(); - let mut routing_handlers_concrete: Vec> = Vec::new(); - for _ in 0..2 { - let routing_handler = Arc::new(TestRoutingMessageHandler::new()); - routing_handlers.push(routing_handler.clone()); - routing_handlers_concrete.push(routing_handler.clone()); - } - let peers = create_network(2, &chan_handlers, Some(&routing_handlers)); + let cfgs = create_peermgr_cfgs(2); + cfgs[0].routing_handler.request_full_sync.store(true, Ordering::Release); + cfgs[1].routing_handler.request_full_sync.store(true, Ordering::Release); + let peers = create_network(2, &cfgs); // By calling establish_connect, we trigger do_attempt_write_data between // the peers. Previously this function would mistakenly enter an infinite loop @@ -1475,22 +1440,19 @@ mod tests { // Check that each peer has received the expected number of channel updates and channel // announcements. - assert_eq!(routing_handlers_concrete[0].clone().chan_upds_recvd.load(Ordering::Acquire), 100); - assert_eq!(routing_handlers_concrete[0].clone().chan_anns_recvd.load(Ordering::Acquire), 50); - assert_eq!(routing_handlers_concrete[1].clone().chan_upds_recvd.load(Ordering::Acquire), 100); - assert_eq!(routing_handlers_concrete[1].clone().chan_anns_recvd.load(Ordering::Acquire), 50); + assert_eq!(cfgs[0].routing_handler.chan_upds_recvd.load(Ordering::Acquire), 100); + assert_eq!(cfgs[0].routing_handler.chan_anns_recvd.load(Ordering::Acquire), 50); + assert_eq!(cfgs[1].routing_handler.chan_upds_recvd.load(Ordering::Acquire), 100); + assert_eq!(cfgs[1].routing_handler.chan_anns_recvd.load(Ordering::Acquire), 50); } #[test] fn limit_initial_routing_sync_requests() { // Inbound peer 0 requests initial_routing_sync, but outbound peer 1 does not. { - let chan_handlers = create_chan_handlers(2); - let routing_handlers: Vec> = vec![ - Arc::new(test_utils::TestRoutingMessageHandler::new().set_request_full_sync()), - Arc::new(test_utils::TestRoutingMessageHandler::new()), - ]; - let peers = create_network(2, &chan_handlers, Some(&routing_handlers)); + let cfgs = create_peermgr_cfgs(2); + cfgs[0].routing_handler.request_full_sync.store(true, Ordering::Release); + let peers = create_network(2, &cfgs); let (fd_0_to_1, fd_1_to_0) = establish_connection_and_read_events(&peers[0], &peers[1]); let peer_0 = peers[0].peers.lock().unwrap(); @@ -1505,12 +1467,9 @@ mod tests { // Outbound peer 1 requests initial_routing_sync, but inbound peer 0 does not. { - let chan_handlers = create_chan_handlers(2); - let routing_handlers: Vec> = vec![ - Arc::new(test_utils::TestRoutingMessageHandler::new()), - Arc::new(test_utils::TestRoutingMessageHandler::new().set_request_full_sync()), - ]; - let peers = create_network(2, &chan_handlers, Some(&routing_handlers)); + let cfgs = create_peermgr_cfgs(2); + cfgs[1].routing_handler.request_full_sync.store(true, Ordering::Release); + let peers = create_network(2, &cfgs); let (fd_0_to_1, fd_1_to_0) = establish_connection_and_read_events(&peers[0], &peers[1]); let peer_0 = peers[0].peers.lock().unwrap(); From a4fff76fd9374f29f0d8daa30e8f6d74182e1c41 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Fri, 12 Jun 2020 19:33:42 -0700 Subject: [PATCH 27/96] Fix unit tests --- fuzz/src/full_stack.rs | 20 +++--- lightning-net-tokio/src/lib.rs | 18 +++--- lightning/src/ln/peers/handler.rs | 103 +++++++++++++++--------------- 3 files changed, 71 insertions(+), 70 deletions(-) diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs index df3b20b0386..090758b1682 100644 --- a/fuzz/src/full_stack.rs +++ b/fuzz/src/full_stack.rs @@ -22,7 +22,7 @@ use lightning::chain::transaction::OutPoint; use lightning::chain::keysinterface::{InMemoryChannelKeys, KeysInterface}; use lightning::ln::channelmonitor; use lightning::ln::channelmanager::{ChannelManager, PaymentHash, PaymentPreimage, PaymentSecret}; -use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor}; +use lightning::ln::peers::handler::{MessageHandler,PeerManager,SocketDescriptor}; use lightning::routing::router::get_route; use lightning::routing::network_graph::NetGraphMsgHandler; use lightning::util::events::{EventsProvider,Event}; @@ -892,15 +892,15 @@ mod tests { super::do_test(&::hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000001000300000000000000000000000000000000000000000000000000000000000000000300320003000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000030012000a0300000000000000000000000000000003001a00100002200000022000030000000000000000000000000000000300120141030000000000000000000000000000000300fe00207500000000000000000000000000000000000000000000000000000000000000ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679000000000000c35000000000000000000000000000000222ffffffffffffffff00000000000002220000000000000000000000fd000601e3030000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000000000000000000000000000000000002030000000000000000000000000000000000000000000000000000000000000003030000000000000000000000000000000000000000000000000000000000000004030053030000000000000000000000000000000000000000000000000000000000000005030000000000000000000000000000000000000000000000000000000000000000010300000000000000000000000000000000fd00fd00fd0300120084030000000000000000000000000000000300940022ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb1819096793d00000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001030000000000000000000000000000000c005e020000000100000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0150c3000000000000220020ae00000000000000000000000000000000000000000000000000000000000000000000000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c00000c000003001200430300000000000000000000000000000003005300243d0000000000000000000000000000000000000000000000000000000000000003010000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000010301320003000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000030142000302000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003000000000000000000000000000000030112000a0100000000000000000000000000000003011a0010000220000002200001000000000000000000000000000000050103020000000000000000000000000000000000000000000000000000000000000000c3500003e800fd00fd00fd0301120110010000000000000000000000000000000301ff00210000000000000000000000000000000000000000000000000000000000000e02000000000000001a00000000004c4b4000000000000003e800000000000003e80000000203f00005030000000000000000000000000000000000000000000000000000000000000100030000000000000000000000000000000000000000000000000000000000000200030000000000000000000000000000000000000000000000000000000000000300030000000000000000000000000000000000000000000000000000000000000400030000000000000000000000000000000000000000000000000000000000000500030000000000000000000000000000000301210000000000000000000000000000000000010000000000000000000000000000000a03011200620100000000000000000000000000000003017200233900000000000000000000000000000000000000000000000000000000000000f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100010000000000000000000000000000000b030112004301000000000000000000000000000000030153002439000000000000000000000000000000000000000000000000000000000000000301000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003e80ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e80000007b0000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000003100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030200000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000f100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003020000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112004a0100000000000000000000000000000003015a008239000000000000000000000000000000000000000000000000000000000000000000000000000000ff008888888888888888888888888888888888888888888888888888888888880100000000000000000000000000000003011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fd0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000010000000000000000000000000000000301120063010000000000000000000000000000000301730085390000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d0000000000000000000000000000000000000000000000000000000000000000000000000000010000000000003e80ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e000001000000000000000003e80000007b0000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200630300000000000000000000000000000003007300853d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000303000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d00000000000000000000000000000000000000000000000000000000000000c200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000030400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000703011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000003011200630100000000000000000000000000000003017300853900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003040000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000030112002c0100000000000000000000000000000003013c00833900000000000000000000000000000000000000000000000000000000000000000000000000000100000100000000000000000000000000000003011200640100000000000000000000000000000003017400843900000000000000000000000000000000000000000000000000000000000000fb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000030112006301000000000000000000000000000000030173008539000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000030500000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000703001200630300000000000000000000000000000003007300853d0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000305000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000003001200640300000000000000000000000000000003007400843d000000000000000000000000000000000000000000000000000000000000003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000300000000000000000000000000000003001205ac030000000000000000000000000000000300ff00803d00000000000000000000000000000000000000000000000000000000000000000000000000000200000000000b0838ff0000000000000000000000000000000000000000000000000000000000000000000121000300000000000000000000000000000000000000000000000000000000000005550000000e0000010000000000000003e8000000007b0000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0300c1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff95000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000fd03001200a4030000000000000000000000000000000300b400843d000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001c8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007f000000000000000300000000000000000000000000000003001200630300000000000000000000000000000003007300853d00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000003060000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000070c007d02000000013900000000000000000000000000000000000000000000000000000000000000000000000000000080020001000000000000220020bb000000000000000000000000000000000000000000000000000000000000006cc10000000000001600142b000000000000000000000000000000000000000500002000fd00fd0c005e0200000001a100000000000000000000000000000000000000000000000000000000000000000000000000000000014f00000000000000220020f600000000000000000000000000000000000000000000000000000000000000000000000c00000c000000fd0c00000c00000c000007").unwrap(), &(Arc::clone(&logger) as Arc)); let log_entries = logger.lines.lock().unwrap(); - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingSigned event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 2 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 3 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 4 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling SendRevokeAndACK event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&4)); // 5 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 6 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 1 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 8 - assert_eq!(log_entries.get(&("lightning::ln::peer_handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 1 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 9 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendAcceptChannel event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel ff4f00f805273c1b203bb5ebf8436bfde57b3be8c2f5e95d9491dbb181909679".to_string())), Some(&1)); // 1 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingSigned event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 2 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 3 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendFundingLocked event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 4 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling SendRevokeAndACK event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&4)); // 5 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 6 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030200000000000000000000000000000000000000000000000000000000000000 with 1 adds, 0 fulfills, 0 fails for channel 3900000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&3)); // 7 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 1 fulfills, 0 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&1)); // 8 + assert_eq!(log_entries.get(&("lightning::ln::peers::handler".to_string(), "Handling UpdateHTLCs event in peer_handler for node 030000000000000000000000000000000000000000000000000000000000000000 with 0 adds, 0 fulfills, 1 fails for channel 3d00000000000000000000000000000000000000000000000000000000000000".to_string())), Some(&2)); // 9 assert_eq!(log_entries.get(&("lightning::ln::channelmonitor".to_string(), "Input spending remote commitment tx (00000000000000000000000000000000000000000000000000000000000000a1:0) in 0000000000000000000000000000000000000000000000000000000000000018 resolves outbound HTLC with payment hash ff00000000000000000000000000000000000000000000000000000000000000 with timeout".to_string())), Some(&1)); // 10 } } diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index d2494d270ee..402a6bc7d5e 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -28,7 +28,7 @@ //! type ChainWatchInterface = dyn lightning::chain::chaininterface::ChainWatchInterface; //! type ChannelMonitor = lightning::ln::channelmonitor::SimpleManyChannelMonitor, Arc, Arc, Arc>; //! type ChannelManager = lightning::ln::channelmanager::SimpleArcChannelManager; -//! type PeerManager = lightning::ln::peer_handler::SimpleArcPeerManager; +//! type PeerManager = lightning::ln::peers::handler::SimpleArcPeerManager; //! //! // Connect to node with pubkey their_node_id at addr: //! async fn connect_to_node(peer_manager: PeerManager, channel_monitor: Arc, channel_manager: ChannelManager, their_node_id: PublicKey, addr: SocketAddr) { @@ -68,8 +68,8 @@ use tokio::{io, time}; use tokio::sync::mpsc; use tokio::io::{AsyncReadExt, AsyncWrite, AsyncWriteExt}; -use lightning::ln::peer_handler; -use lightning::ln::peer_handler::SocketDescriptor as LnSocketTrait; +use lightning::ln::peers::handler; +use lightning::ln::peers::handler::SocketDescriptor as LnSocketTrait; use lightning::ln::msgs::{ChannelMessageHandler, RoutingMessageHandler}; use lightning::util::logger::Logger; @@ -124,7 +124,7 @@ impl Connection { _ => panic!() } } - async fn schedule_read(peer_manager: Arc, Arc, Arc>>, us: Arc>, mut reader: io::ReadHalf, mut read_wake_receiver: mpsc::Receiver<()>, mut write_avail_receiver: mpsc::Receiver<()>) where + async fn schedule_read(peer_manager: Arc, Arc, Arc>>, us: Arc>, mut reader: io::ReadHalf, mut read_wake_receiver: mpsc::Receiver<()>, mut write_avail_receiver: mpsc::Receiver<()>) where CMH: ChannelMessageHandler + 'static, RMH: RoutingMessageHandler + 'static, L: Logger + 'static + ?Sized { @@ -237,7 +237,7 @@ impl Connection { /// not need to poll the provided future in order to make progress. /// /// See the module-level documentation for how to handle the event_notify mpsc::Sender. -pub fn setup_inbound(peer_manager: Arc, Arc, Arc>>, event_notify: mpsc::Sender<()>, stream: TcpStream) -> impl std::future::Future where +pub fn setup_inbound(peer_manager: Arc, Arc, Arc>>, event_notify: mpsc::Sender<()>, stream: TcpStream) -> impl std::future::Future where CMH: ChannelMessageHandler + 'static, RMH: RoutingMessageHandler + 'static, L: Logger + 'static + ?Sized { @@ -279,7 +279,7 @@ pub fn setup_inbound(peer_manager: Arc(peer_manager: Arc, Arc, Arc>>, event_notify: mpsc::Sender<()>, their_node_id: PublicKey, stream: TcpStream) -> impl std::future::Future where +pub fn setup_outbound(peer_manager: Arc, Arc, Arc>>, event_notify: mpsc::Sender<()>, their_node_id: PublicKey, stream: TcpStream) -> impl std::future::Future where CMH: ChannelMessageHandler + 'static, RMH: RoutingMessageHandler + 'static, L: Logger + 'static + ?Sized { @@ -351,7 +351,7 @@ pub fn setup_outbound(peer_manager: Arc(peer_manager: Arc, Arc, Arc>>, event_notify: mpsc::Sender<()>, their_node_id: PublicKey, addr: SocketAddr) -> Option> where +pub async fn connect_outbound(peer_manager: Arc, Arc, Arc>>, event_notify: mpsc::Sender<()>, their_node_id: PublicKey, addr: SocketAddr) -> Option> where CMH: ChannelMessageHandler + 'static, RMH: RoutingMessageHandler + 'static, L: Logger + 'static + ?Sized { @@ -402,7 +402,7 @@ impl SocketDescriptor { Self { conn, id } } } -impl peer_handler::SocketDescriptor for SocketDescriptor { +impl handler::SocketDescriptor for SocketDescriptor { fn send_data(&mut self, data: &[u8], resume_read: bool) -> usize { // To send data, we take a lock on our Connection to access the WriteHalf of the TcpStream, // writing to it if there's room in the kernel buffer, or otherwise create a new Waker with @@ -494,7 +494,7 @@ impl Hash for SocketDescriptor { mod tests { use lightning::ln::features::*; use lightning::ln::msgs::*; - use lightning::ln::peer_handler::{MessageHandler, PeerManager}; + use lightning::ln::peers::handler::{MessageHandler, PeerManager}; use lightning::util::events::*; use bitcoin::secp256k1::{Secp256k1, SecretKey, PublicKey}; diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 241573045e0..54e996214ce 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -544,7 +544,7 @@ impl PeerManager peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!($msg)[..])), + PeerState::Connected(ref mut conduit) => peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_message[..])), _ => panic!("peer must be connected!") } peers_needing_send.insert(descriptor); @@ -563,7 +563,7 @@ impl PeerManager { - log_trace!(self, "Invalid act message; disconnecting: {}", e); + log_trace!(self.logger, "Invalid act message; disconnecting: {}", e); return Err(e); } @@ -577,12 +577,12 @@ impl PeerManager { - log_trace!(self, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); + log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); peer.their_node_id = None; // Unset so that we don't generate a peer_disconnected event return Err(PeerHandleError { no_connection_possible: false }); } hash_map::Entry::Vacant(entry) => { - log_trace!(self, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); + log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); entry.insert(peer_descriptor.clone()) } }; @@ -590,48 +590,22 @@ impl PeerManager {} }; - if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { + if send_init_message { + let mut features = InitFeatures::known(); + if !self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.clear_initial_routing_sync(); + } + + let resp = msgs::Init { features }; + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); + send_init_message = false + } + let mut received_messages = vec![]; + if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { let encryptor = &mut conduit.encryptor; let decryptor = &mut conduit.decryptor; - macro_rules! try_potential_handleerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(e) => { - match e.action { - msgs::ErrorAction::DisconnectPeer { msg: _ } => { - //TODO: Try to push msg - log_trace!(self.logger, "Got Err handling message, disconnecting peer because {}", e.err); - return Err(PeerHandleError{ no_connection_possible: false }); - }, - msgs::ErrorAction::IgnoreError => { - log_trace!(self.logger, "Got Err handling message, ignoring because {}", e.err); - continue; - }, - msgs::ErrorAction::SendErrorMessage { msg } => { - log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &msg); - continue; - }, - } - } - }; - } - } - - if send_init_message { - let mut features = InitFeatures::known(); - if !self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.clear_initial_routing_sync(); - } - - let resp = msgs::Init { features }; - self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); - send_init_message = false - } - for msg_data in decryptor { let mut reader = ::std::io::Cursor::new(&msg_data[..]); let message_result = wire::read(&mut reader); @@ -658,16 +632,43 @@ impl PeerManager { return Err(e) }, - MessageHandlingError::LightningError(e) => { - try_potential_handleerror!(Err(e)); - }, - } + received_messages.push(message); + } + } + + for message in received_messages { + macro_rules! try_potential_handleerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(e) => { + match e.action { + msgs::ErrorAction::DisconnectPeer { msg: _ } => { + //TODO: Try to push msg + log_trace!(self.logger, "Got Err handling message, disconnecting peer because {}", e.err); + return Err(PeerHandleError{ no_connection_possible: false }); + }, + msgs::ErrorAction::IgnoreError => { + log_trace!(self.logger, "Got Err handling message, ignoring because {}", e.err); + continue; + }, + msgs::ErrorAction::SendErrorMessage { msg } => { + log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &msg); + continue; + }, } } - } + }; + } + } + + if let Err(handling_error) = self.handle_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), message){ + match handling_error { + MessageHandlingError::PeerHandleError(e) => { return Err(e) }, + MessageHandlingError::LightningError(e) => { + try_potential_handleerror!(Err(e)); + }, } } } @@ -1267,7 +1268,7 @@ impl PeerManager Date: Sun, 16 Aug 2020 15:39:59 -0700 Subject: [PATCH 28/96] tests: Add unit tests to handshake/mod.rs Add unit tests against the PeerHandshake public interface prior to changing any of the implementation details. This is a solid stand-alone patch, even if the subsequent refactor and design changes are not merged. A future patch uses the test vectors from the RFC to minimize the code under test. --- lightning/src/ln/peers/conduit.rs | 10 + lightning/src/ln/peers/handshake/mod.rs | 371 ++++++++++++++++++++++++ 2 files changed, 381 insertions(+) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 74e420b192a..c921e81935f 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -196,6 +196,16 @@ impl Decryptor { fn increment_nonce(&mut self) { Conduit::increment_nonce(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); } + + // Used in tests to determine whether or not excess bytes entered the conduit without needing to bring up + // infrastructure to properly encode it + #[cfg(test)] + pub fn read_buffer_length(&self) -> usize { + match &self.read_buffer { + &Some(ref vec) => { vec.len() } + &None => 0 + } + } } #[cfg(test)] diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 32efc969a22..2d95998aa2e 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -392,3 +392,374 @@ impl PeerHandshake { Sha256::from_engine(sha).into_inner() } } + +#[cfg(test)] +mod test { + use hex; + + use bitcoin::secp256k1; + use bitcoin::secp256k1::key::{PublicKey, SecretKey}; + + use ln::peers::handshake::PeerHandshake; + use ln::peers::handshake::acts::Act; + use ln::peers::handshake::states::HandshakeState; + + struct TestCtx { + outbound_handshake: PeerHandshake, + outbound_public_key: PublicKey, + inbound_handshake: PeerHandshake, + inbound_public_key: PublicKey + } + + impl TestCtx { + fn new() -> TestCtx { + let curve = secp256k1::Secp256k1::new(); + + let outbound_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let outbound_public_key = PublicKey::from_secret_key(&curve, &outbound_private_key); + let outbound_ephemeral_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); + + let inbound_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let inbound_public_key = PublicKey::from_secret_key(&curve, &inbound_private_key); + let inbound_ephemeral_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); + + let outbound_handshake = PeerHandshake::new_outbound(&outbound_private_key, &inbound_public_key, &outbound_ephemeral_key); + let inbound_handshake = PeerHandshake::new_inbound(&inbound_private_key, &inbound_ephemeral_key); + + TestCtx { + outbound_handshake, + outbound_public_key, + inbound_handshake, + inbound_public_key + } + } + } + + macro_rules! assert_matches { + ($e:expr, $state_match:pat) => { + match $e { + $state_match => (), + _ => panic!() + } + } + } + + macro_rules! do_process_act_or_panic { + ($handshake:expr, $input:expr) => { + $handshake.process_act($input).unwrap().0.unwrap().serialize() + } + } + + // Default Outbound::Uninitiated + #[test] + fn peer_handshake_new_outbound() { + let test_ctx = TestCtx::new(); + + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::Uninitiated)); + assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); + } + + // Default Inbound::AwaitingActOne + #[test] + fn peer_handshake_new_inbound() { + let test_ctx = TestCtx::new(); + + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::AwaitingActOne(_))); + assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); + } + + /* + * PeerHandshake::process_act() tests + */ + + // Outbound::Uninitiated -> AwaitingActTwo + #[test] + fn peer_handshake_outbound_uninitiated_to_awaiting_act_two() { + let mut test_ctx = TestCtx::new(); + + assert_matches!(test_ctx.outbound_handshake.process_act(&[]).unwrap(), (Some(Act::One(_)), None)); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::AwaitingActTwo(_))); + assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); + } + + // Outbound::Uninitiated -> AwaitingActTwo (extra bytes in argument) + #[test] + fn peer_handshake_outbound_uninitiated_to_awaiting_act_two_nonempty_input() { + let mut test_ctx = TestCtx::new(); + + // TODO: process_act() should error if state does not use vec, but it is non-empty + assert_matches!(test_ctx.outbound_handshake.process_act(&[1]).unwrap(), (Some(Act::One(_)), None)); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::AwaitingActTwo(_))); + assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); + } + + // Inbound::AwaitingActOne -> Error (input too small) + #[test] + fn peer_handshake_new_inbound_awaiting_act_one_input_too_small() { + let mut test_ctx = TestCtx::new(); + + assert_eq!(test_ctx.inbound_handshake.process_act(&[]).err(), Some(String::from("need at least 50 bytes"))); + } + + // Inbound::AwaitingActOne -> AwaitingActThree (excess bytes) + // TODO: This should error early if we receive act3 data prior to sending act2 + #[test] + fn peer_handshake_new_inbound_awaiting_act_one_input_too_large() { + let mut test_ctx = TestCtx::new(); + let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + act1.extend_from_slice(&[1]); + + assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(Act::Two(_)), None)); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::AwaitingActThree(_))); + assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); + } + + // Inbound::AwaitingActOne -> Error (bad version byte) + #[test] + fn peer_handshake_new_inbound_awaiting_act_one_bad_version() { + let mut test_ctx = TestCtx::new(); + let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + // Set bad version byte + act1[0] = 1; + + assert_eq!(test_ctx.inbound_handshake.process_act(&act1).err(), Some(String::from("unexpected version"))); + } + + // Inbound::AwaitingActOne -> Error (invalid hmac) + #[test] + fn peer_handshake_new_inbound_awaiting_act_invalid_hmac() { + let mut test_ctx = TestCtx::new(); + let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + // corrupt the ciphertext + act1[34] = 0; + + assert_eq!(test_ctx.inbound_handshake.process_act(&act1).err(), Some(String::from("invalid hmac"))); + } + + // Inbound::AwaitingActOne -> Error (invalid remote ephemeral key) + #[test] + fn peer_handshake_new_inbound_awaiting_act_invalid_remote_ephemeral_key() { + let mut test_ctx = TestCtx::new(); + let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + // corrupt the ephemeral public key + act1[1] = 0; + + assert_eq!(test_ctx.inbound_handshake.process_act(&act1).err(), Some(String::from("invalid remote ephemeral public key"))); + } + + // Inbound::AwaitingActOne -> AwaitingActThree + #[test] + fn peer_handshake_new_inbound_awaiting_act_one_to_awaiting_act_three() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + + assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(Act::Two(_)), None)); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::AwaitingActThree(_))); + assert_eq!(test_ctx.inbound_handshake.get_remote_pubkey(), None); + } + + // Outbound::AwaitingActTwo -> Complete (valid conduit) + #[test] + fn peer_handshake_outbound_awaiting_act_two_process() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + + assert_matches!(test_ctx.outbound_handshake.process_act(&act2).unwrap(), (Some(Act::Three(_)), Some(_))); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::Complete)); + assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); + } + + + // Outbound::AwaitingActTwo -> Complete (with extra data) + // Ensures that any remaining data in the read buffer is transferred to the conduit once + // the handshake is complete + // TODO: Is this valid? Don't we expect peers to need ActThree before sending additional data? + #[test] + fn peer_handshake_new_outbound_excess_bytes_after_complete_are_in_conduit() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + act2.extend_from_slice(&[1; 100]); + + let conduit = if let (_, Some(conduit)) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { + conduit + } else { + panic!(); + }; + + assert_eq!(100, conduit.decryptor.read_buffer_length()); + assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); + } + + // Outbound::AwaitingActTwo -> Error (input too small) + #[test] + fn peer_handshake_outbound_awaiting_act_two_input_too_small() { + let mut test_ctx = TestCtx::new(); + let _act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + + assert_eq!(test_ctx.outbound_handshake.process_act(&[1]).err(), Some(String::from("need at least 50 bytes"))); + } + + // Outbound::AwaitingActTwo -> Error (bad version byte) + #[test] + fn peer_handshake_outbound_awaiting_act_two_bad_version() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + // Set version byte to 1 + act2[0] = 1; + + assert_eq!(test_ctx.outbound_handshake.process_act(&act2).err(), Some(String::from("unexpected version"))); + } + + // Outbound::AwaitingActTwo -> Error (invalid hmac) + #[test] + fn peer_handshake_outbound_awaiting_act_two_invalid_hmac() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + // corrupt the ciphertext + act2[34] = 1; + + assert_eq!(test_ctx.outbound_handshake.process_act(&act2).err(), Some(String::from("invalid hmac"))); + } + + // Outbound::AwaitingActTwo -> Error (invalid remote ephemeral key) + #[test] + fn peer_handshake_outbound_awaiting_act_two_invalid_remote_ephemeral_key() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + // corrupt the ephemeral public key + act2[1] = 1; + + assert_eq!(test_ctx.outbound_handshake.process_act(&act2).err(), Some(String::from("invalid remote ephemeral public key"))); + } + + // Inbound::AwaitingActThree -> None + // TODO: should this transition to Complete instead of None? + #[test] + fn peer_handshake_new_inbound_awaiting_act_three_to_awaiting_act_three() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + + assert_matches!(test_ctx.inbound_handshake.process_act(&act3).unwrap(), (None, Some(_))); + assert_eq!(test_ctx.inbound_handshake.get_remote_pubkey(), Some(test_ctx.outbound_public_key)); + } + + // Inbound::AwaitingActThree -> None (with extra bytes) + // Ensures that any remaining data in the read buffer is transferred to the conduit once + // the handshake is complete + #[test] + fn peer_handshake_new_inbound_excess_bytes_after_complete_are_in_conduit() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + act3.extend_from_slice(&[2; 100]); + + let conduit = if let (None, Some(conduit)) = test_ctx.inbound_handshake.process_act(&act3).unwrap() { + conduit + } else { + panic!(); + }; + + assert_eq!(100, conduit.decryptor.read_buffer_length()); + } + + // Inbound::AwaitingActThree -> Error (input too small) + #[test] + fn peer_handshake_new_inbound_awaiting_act_three_input_too_small() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + + assert_eq!(test_ctx.inbound_handshake.process_act(&act3[..65]).err(), Some(String::from("need at least 66 bytes"))); + } + + // Inbound::AwaitingActThree -> Error (bad version byte) + #[test] + fn peer_handshake_new_inbound_awaiting_act_three_bad_version() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + // set version byte to 1 + act3[0] = 1; + + assert_eq!(test_ctx.inbound_handshake.process_act(&act3).err(), Some(String::from("unexpected version"))); + } + + // Inbound::AwaitingActThree -> Error (invalid hmac) + #[test] + fn peer_handshake_new_inbound_awaiting_act_three_invalid_hmac() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + // trigger decryption error by corrupting byte 1 + act3[1] = 0; + + assert_eq!(test_ctx.inbound_handshake.process_act(&act3).err(), Some(String::from("invalid hmac"))); + } + + // Inbound::AwaitingActThree -> Error (invalid tag hmac) + #[test] + fn peer_handshake_new_inbound_awaiting_act_three_invalid_tag_hmac() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + // trigger tag decryption error by corrupting byte 50 + act3[50] = 0; + + assert_eq!(test_ctx.inbound_handshake.process_act(&act3).err(), Some(String::from("invalid hmac"))); + } + + // Inbound::Complete -> Panic + #[test] + #[should_panic(expected = "no acts left to process")] + fn peer_handshake_new_inbound_complete_then_process_act() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + test_ctx.inbound_handshake.process_act(&act3).unwrap(); + + do_process_act_or_panic!(test_ctx.inbound_handshake, &[]); + } + + // Outbound::None -> Panic + #[test] + #[should_panic(expected = "no acts left to process")] + fn peer_handshake_new_outbound_complete_then_process_act() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + test_ctx.inbound_handshake.process_act(&act3).unwrap(); + + do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + } + + // Test the Act byte generation against known good hard-coded values in case the implementation + // changes in a symmetric way that makes the other tests useless + #[test] + fn peer_handshake_external_spec() { + let mut test_ctx = TestCtx::new(); + let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); + + assert_eq!(hex::encode(&act1), + "00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a"); + assert_eq!(hex::encode(&act2), + "0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae"); + assert_eq!(hex::encode(&act3), + "00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"); + } +} From 65e4340f6c7087c95a32d3585106dc4a0cd6933d Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sun, 16 Aug 2020 21:13:48 -0700 Subject: [PATCH 29/96] delete: Remove duplicate tests --- lightning/src/ln/peers/handler.rs | 1 - lightning/src/ln/peers/handshake/mod.rs | 11 +++---- lightning/src/ln/peers/handshake/tests.rs | 39 ----------------------- 3 files changed, 5 insertions(+), 46 deletions(-) delete mode 100644 lightning/src/ln/peers/handshake/tests.rs diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 54e996214ce..b8a2d076b64 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -32,7 +32,6 @@ use bitcoin::hashes::sha256::HashEngine as Sha256Engine; use bitcoin::hashes::{HashEngine, Hash}; use ln::peers::handshake::PeerHandshake; use ln::peers::conduit::Conduit; -use ln::peers::handshake::acts::Act; /// Provides references to trait impls which handle different types of messages. pub struct MessageHandler where diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 2d95998aa2e..babdb32129b 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -14,10 +14,9 @@ use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo, ACT_ONE_LENGTH, ACT_T use ln::peers::handshake::hash::HandshakeHash; use ln::peers::handshake::states::{ActOneExpectation, ActThreeExpectation, ActTwoExpectation, HandshakeState}; -pub(crate) mod acts; +mod acts; mod hash; mod states; -mod tests; /// Object for managing handshakes. /// Currently requires explicit ephemeral private key specification. @@ -162,7 +161,7 @@ impl PeerHandshake { } /// Initiate the handshake with a peer and return the first act - pub fn initiate(&mut self, remote_public_key: &PublicKey) -> Result { + fn initiate(&mut self, remote_public_key: &PublicKey) -> Result { if let &Some(HandshakeState::Uninitiated) = &self.state {} else { return Err("Handshakes can only be initiated from the uninitiated state".to_string()); } @@ -188,7 +187,7 @@ impl PeerHandshake { } /// Process a peer's incoming first act and return the second act - pub(crate) fn process_act_one(&mut self, act: ActOne) -> Result { + fn process_act_one(&mut self, act: ActOne) -> Result { let state = self.state.take(); let act_one_expectation = match state { Some(HandshakeState::AwaitingActOne(act_state)) => act_state, @@ -235,7 +234,7 @@ impl PeerHandshake { } /// Process a peer's incoming second act and return the third act alongside a Conduit instance - pub(crate) fn process_act_two(&mut self, act: ActTwo) -> Result<(ActThree, Conduit), String> { + fn process_act_two(&mut self, act: ActTwo) -> Result<(ActThree, Conduit), String> { let state = self.state.take(); let act_two_expectation = match state { Some(HandshakeState::AwaitingActTwo(act_state)) => act_state, @@ -275,7 +274,7 @@ impl PeerHandshake { } /// Process a peer's incoming third act and return a Conduit instance - pub(crate) fn process_act_three(&mut self, act: ActThree) -> Result<(PublicKey, Conduit), String> { + fn process_act_three(&mut self, act: ActThree) -> Result<(PublicKey, Conduit), String> { let state = self.state.take(); let act_three_expectation = match state { Some(HandshakeState::AwaitingActThree(act_state)) => act_state, diff --git a/lightning/src/ln/peers/handshake/tests.rs b/lightning/src/ln/peers/handshake/tests.rs deleted file mode 100644 index e99500d1399..00000000000 --- a/lightning/src/ln/peers/handshake/tests.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![cfg(test)] - -use hex; -use bitcoin::secp256k1; - -use bitcoin::secp256k1::key::{PublicKey, SecretKey}; - -use ln::peers::handshake::PeerHandshake; - -#[test] -fn test_exchange() { - let curve = secp256k1::Secp256k1::new(); - - let local_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); - let remote_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); - - let local_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); - let remote_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - - let remote_public_key = PublicKey::from_secret_key(&curve, &remote_private_key); - - let mut local_handshake = PeerHandshake::new_outbound(&local_private_key, &remote_public_key, &local_ephemeral_private_key); - let mut remote_handshake = PeerHandshake::new_inbound(&remote_private_key, &remote_ephemeral_private_key); - - let act_1 = local_handshake.initiate(&remote_public_key).unwrap(); - let act_1_hex = hex::encode(&act_1.0.to_vec()); - assert_eq!(act_1_hex, "00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a"); - - let act_2 = remote_handshake.process_act_one(act_1).unwrap(); - let act_2_hex = hex::encode(&act_2.0.to_vec()); - assert_eq!(act_2_hex, "0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae"); - - let act_2_result = local_handshake.process_act_two(act_2).unwrap(); - let act_3 = act_2_result.0; - let act_3_hex = hex::encode(&act_3.0.to_vec()); - assert_eq!(act_3_hex, "00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"); - - remote_handshake.process_act_three(act_3).unwrap(); -} From 12df425d2e6052269d7d414d8b32403004ac9b58 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 17 Aug 2020 15:32:56 -0700 Subject: [PATCH 30/96] refactor: Create enum-dispatch NOISE state machine The implementation logic is duplicated from handshake/mod.rs so that it can be tested and refactored independent of the current implementation. This uses enum dispatch coupled with separately 'moved' state objects that allow for simple testing, easy state inspection, and understandable transition logic between states. This pattern also removes the need for match statements inside implementation logic in favor of the instance representing the current state and available data. Every state transition is implemented in a next() function and is a straight forward translation from an object representing the existing known data and an input act message (bytes). Example usage: let (act_data, next_state) = cur_state.next(input_data); This state machine will eventually be moved into place inside the PeerHandshake which will act as a simple wrapper that just maintains the state machine and marshals the data between the peer_handler and states. --- lightning/src/ln/peers/handshake/states.rs | 661 ++++++++++++++++++++- 1 file changed, 660 insertions(+), 1 deletion(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 2a7401f5e9b..3f2649bfdd8 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -1,6 +1,14 @@ -use ln::peers::handshake::hash::HandshakeHash; +use bitcoin::secp256k1; + use bitcoin::secp256k1::{SecretKey, PublicKey}; +use ln::peers::handshake::hash::HandshakeHash; +use ln::peers::handshake::acts::{Act, ActOne, ACT_ONE_LENGTH, ActTwo, ACT_TWO_LENGTH, ACT_THREE_LENGTH, ActThree}; +use ln::peers::handshake::states::HandshakeState2::{AwaitingActTwo2, AwaitingActThree2, Complete2}; +use ln::peers::handshake::PeerHandshake; +use ln::peers::{chacha, hkdf}; +use ln::peers::conduit::Conduit; + pub enum HandshakeState { Uninitiated, AwaitingActOne(ActOneExpectation), @@ -9,6 +17,298 @@ pub enum HandshakeState { Complete, } +pub enum HandshakeState2 { + Uninitiated2(UninitiatedHandshakeState), + AwaitingActOne2(AwaitingActOneHandshakeState), + AwaitingActTwo2(AwaitingActTwoHandshakeState), + AwaitingActThree2(AwaitingActThreeHandshakeState), + Complete2(Option<(Conduit, PublicKey)>), +} + +impl HandshakeState2 { + pub(crate) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + match self { + HandshakeState2::Uninitiated2(state) => { state.next(input) }, + HandshakeState2::AwaitingActOne2(state) => { state.next(input) }, + HandshakeState2::AwaitingActTwo2(state) => { state.next(input) }, + HandshakeState2::AwaitingActThree2(state) => { state.next(input) }, + HandshakeState2::Complete2(_conduit) => { panic!("no acts left to process") } + } + } +} + +trait IHandshakeState { + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String>; +} + +pub struct UninitiatedHandshakeState { + initiator_private_key: SecretKey, + initiator_ephemeral_private_key: SecretKey, + responder_public_key: PublicKey, +} + +pub struct AwaitingActOneHandshakeState { + responder_private_key: SecretKey, + responder_ephemeral_private_key: SecretKey, + chaining_key: [u8; 32], + hash: HandshakeHash, + read_buffer: Vec +} + +pub struct AwaitingActTwoHandshakeState { + initiator_private_key: SecretKey, + initiator_ephemeral_private_key: SecretKey, + responder_public_key: PublicKey, + chaining_key: [u8; 32], + hash: HandshakeHash, + read_buffer: Vec +} + +pub struct AwaitingActThreeHandshakeState { + hash: HandshakeHash, + responder_ephemeral_private_key: SecretKey, + chaining_key: [u8; 32], + temporary_key: [u8; 32], + read_buffer: Vec +} + +impl UninitiatedHandshakeState { + pub(crate) fn new(initiator_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_public_key: PublicKey) -> Self { + UninitiatedHandshakeState { + initiator_private_key, + initiator_ephemeral_private_key, + responder_public_key + } + } +} + +impl IHandshakeState for UninitiatedHandshakeState { + fn next(self, _input: &[u8]) -> Result<(Option, HandshakeState2), String> { + + let initiator_private_key = self.initiator_private_key; + let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; + let responder_public_key = self.responder_public_key; + + let (mut hash, chaining_key) = PeerHandshake::initialize_state(&responder_public_key); + + // serialize act one + let (act_one, chaining_key, _) = PeerHandshake::calculate_act_message( + &initiator_ephemeral_private_key, + &responder_public_key, + chaining_key, + &mut hash, + ); + + Ok(( + Some(Act::One(ActOne(act_one))), + AwaitingActTwo2(AwaitingActTwoHandshakeState::new(initiator_private_key, initiator_ephemeral_private_key, responder_public_key, chaining_key, hash)) + )) + } +} + +impl AwaitingActOneHandshakeState { + pub(crate) fn new(responder_private_key: SecretKey, responder_ephemeral_private_key: SecretKey) -> Self { + + let curve = secp256k1::Secp256k1::new(); + let responder_public_key = PublicKey::from_secret_key(&curve, &responder_private_key); + let (hash, chaining_key) = PeerHandshake::initialize_state(&responder_public_key); + + AwaitingActOneHandshakeState { + responder_private_key, + responder_ephemeral_private_key, + chaining_key, + hash, + read_buffer: Vec::new() + } + } +} + +impl IHandshakeState for AwaitingActOneHandshakeState { + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + + let mut read_buffer = self.read_buffer; + read_buffer.extend_from_slice(input); + + if read_buffer.len() < ACT_ONE_LENGTH { + return Err("need at least 50 bytes".to_string()); + } + + let mut hash = self.hash; + let responder_private_key = self.responder_private_key; + let chaining_key = self.chaining_key; + let responder_ephemeral_private_key = self.responder_ephemeral_private_key; + + // common functions take in an array so drain here for now + let mut act_one_bytes = [0u8; ACT_ONE_LENGTH]; + act_one_bytes.copy_from_slice(&read_buffer[..ACT_ONE_LENGTH]); + read_buffer.drain(..ACT_ONE_LENGTH); + + let (initiator_ephemeral_public_key, chaining_key, _) = PeerHandshake::process_act_message( + act_one_bytes, + &responder_private_key, + chaining_key, + &mut hash, + )?; + + let (act_two, chaining_key, temporary_key) = PeerHandshake::calculate_act_message( + &responder_ephemeral_private_key, + &initiator_ephemeral_public_key, + chaining_key, + &mut hash, + ); + + Ok(( + Some(Act::Two(ActTwo(act_two))), + AwaitingActThree2( + AwaitingActThreeHandshakeState::new(hash, responder_ephemeral_private_key, chaining_key, temporary_key, read_buffer) + ) + )) + } +} + +impl IHandshakeState for AwaitingActTwoHandshakeState { + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + + let mut read_buffer = self.read_buffer; + read_buffer.extend_from_slice(input); + + if read_buffer.len() < ACT_TWO_LENGTH { + return Err("need at least 50 bytes".to_string()); + } + + let initiator_private_key = self.initiator_private_key; + let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; + let responder_public_key = self.responder_public_key; + let mut hash = self.hash; + let chaining_key = self.chaining_key; + + // common functions take in an array so drain here for now + let mut act_two_bytes = [0u8; ACT_TWO_LENGTH]; + act_two_bytes.copy_from_slice(&read_buffer[..ACT_TWO_LENGTH]); + read_buffer.drain(..ACT_TWO_LENGTH); + + let (responder_ephemeral_public_key, chaining_key, temporary_key) = PeerHandshake::process_act_message( + act_two_bytes, + &initiator_ephemeral_private_key, + chaining_key, + &mut hash, + )?; + + // start serializing act three + + let curve = secp256k1::Secp256k1::new(); + let initiator_public_key = PublicKey::from_secret_key(&curve, &initiator_private_key); + let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_public_key.serialize()); + hash.update(&tagged_encrypted_pubkey); + + let ecdh = PeerHandshake::ecdh(&initiator_private_key, &responder_ephemeral_public_key); + let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); + let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); + + let mut act_three = [0u8; ACT_THREE_LENGTH]; + act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); + act_three[50..].copy_from_slice(authentication_tag.as_slice()); + + let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); + + if read_buffer.len() > 0 { // have we received more data still? + conduit.read(&read_buffer[..]); + read_buffer.drain(..); + } + + Ok(( + Some(Act::Three(ActThree(act_three))), + Complete2(Some((conduit, responder_public_key))) + )) + } +} + +impl AwaitingActTwoHandshakeState { + fn new(initiator_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_public_key: PublicKey, chaining_key: [u8;32], hash: HandshakeHash) -> Self { + AwaitingActTwoHandshakeState { + initiator_private_key, + initiator_ephemeral_private_key, + responder_public_key, + chaining_key, + hash, + read_buffer: Vec::new() + } + } +} + +impl IHandshakeState for AwaitingActThreeHandshakeState { + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + let mut read_buffer = self.read_buffer; + read_buffer.extend_from_slice(input); + + if read_buffer.len() < ACT_THREE_LENGTH { + return Err("need at least 66 bytes".to_string()); + } + + let mut hash = self.hash; + let temporary_key = self.temporary_key; + let responder_ephemeral_private_key = self.responder_ephemeral_private_key; + let chaining_key = self.chaining_key; + + let mut act_three_bytes = [0u8; ACT_THREE_LENGTH]; + act_three_bytes.copy_from_slice(&read_buffer[..ACT_THREE_LENGTH]); + read_buffer.drain(..ACT_THREE_LENGTH); + + let version = act_three_bytes[0]; + if version != 0 { + // this should not crash the process, hence no panic + return Err("unexpected version".to_string()); + } + + let mut tagged_encrypted_pubkey = [0u8; 49]; + tagged_encrypted_pubkey.copy_from_slice(&act_three_bytes[1..50]); + + let mut chacha_tag = [0u8; 16]; + chacha_tag.copy_from_slice(&act_three_bytes[50..66]); + + let remote_pubkey_vec = chacha::decrypt(&temporary_key, 1, &hash.value, &tagged_encrypted_pubkey)?; + let mut initiator_pubkey_bytes = [0u8; 33]; + initiator_pubkey_bytes.copy_from_slice(remote_pubkey_vec.as_slice()); + let initiator_pubkey = if let Ok(public_key) = PublicKey::from_slice(&initiator_pubkey_bytes) { + public_key + } else { + return Err("invalid remote public key".to_string()); + }; + + hash.update(&tagged_encrypted_pubkey); + + let ecdh = PeerHandshake::ecdh(&responder_ephemeral_private_key, &initiator_pubkey); + let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; + let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); + + let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); + + if read_buffer.len() > 0 { // have we received more data still? + conduit.read(&read_buffer[..]); + read_buffer.drain(..); + } + + Ok(( + None, + Complete2(Some((conduit, initiator_pubkey))) + )) + } +} + +impl AwaitingActThreeHandshakeState { + fn new(hash: HandshakeHash, responder_ephemeral_private_key: SecretKey, chaining_key: [u8; 32], temporary_key: [u8; 32], read_buffer: Vec) -> Self { + AwaitingActThreeHandshakeState { + hash, + responder_ephemeral_private_key, + chaining_key, + temporary_key, + read_buffer + } + } +} + pub struct ActOneExpectation { pub(super) hash: HandshakeHash, pub(super) chaining_key: [u8; 32], @@ -28,3 +328,362 @@ pub struct ActThreeExpectation { pub(super) ephemeral_private_key: SecretKey, pub(super) remote_ephemeral_public_key: PublicKey, } + +#[cfg(test)] +mod test { + use hex; + + use bitcoin::secp256k1; + use bitcoin::secp256k1::{PublicKey, SecretKey}; + + use ln::peers::handshake::acts::Act; + use ln::peers::handshake::states::{UninitiatedHandshakeState, AwaitingActOneHandshakeState, HandshakeState2}; + use ln::peers::handshake::states::HandshakeState2::{AwaitingActThree2, AwaitingActTwo2, Complete2}; + + struct TestCtx { + initiator: HandshakeState2, + initiator_public_key: PublicKey, + responder: HandshakeState2, + responder_public_key: PublicKey + } + + impl TestCtx { + fn new() -> Self { + let curve = secp256k1::Secp256k1::new(); + let initiator_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let initiator_public_key = PublicKey::from_secret_key(&curve, &initiator_private_key); + let initiator_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); + + let responder_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let responder_public_key = PublicKey::from_secret_key(&curve, &responder_private_key); + let responder_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); + + let initiator = UninitiatedHandshakeState::new(initiator_private_key, initiator_ephemeral_private_key, responder_public_key); + let responder = AwaitingActOneHandshakeState::new(responder_private_key, responder_ephemeral_private_key); + + TestCtx { + initiator: HandshakeState2::Uninitiated2(initiator), + initiator_public_key, + responder: HandshakeState2::AwaitingActOne2(responder), + responder_public_key, + } + } + } + + macro_rules! do_next_or_panic { + ($state:expr, $input:expr) => { + if let (Some(output_act), next_state) = $state.next($input).unwrap() { + (output_act.serialize(), next_state) + } else { + panic!(); + } + } + } + + macro_rules! assert_matches { + ($e:expr, $state_match:pat) => { + match $e { + $state_match => (), + _ => panic!() + } + } + } + + // Initiator::Uninitiated -> AwaitingActTwo + #[test] + fn uninitiated_to_awaiting_act_two() { + let test_ctx = TestCtx::new(); + + assert_matches!(test_ctx.initiator.next(&[]).unwrap(), (Some(Act::One(_)), AwaitingActTwo2(_))); + } + + // Initiator::Uninitiated -> AwaitingActTwo (extra bytes in argument) + #[test] + fn uninitiated_to_awaiting_act_two_extra_bytes() { + let test_ctx = TestCtx::new(); + + assert_matches!(test_ctx.initiator.next(&[1]).unwrap(), (Some(Act::One(_)), AwaitingActTwo2(_))); + } + + // Responder::AwaitingActOne -> Error (input too small) + #[test] + fn awaiting_act_one_to_awaiting_act_three_input_too_small() { + let test_ctx = TestCtx::new(); + assert_eq!(test_ctx.responder.next(&[]).err(), Some(String::from("need at least 50 bytes"))) + } + + // Responder::AwaitingActOne -> AwaitingActThree + // TODO: Should this fail since we don't expect data > ACT_ONE_LENGTH and likely indicates + // a bad peer? + // TODO: Should the behavior be changed to handle act1 data that is striped across multiple + // next() calls? + #[test] + fn awaiting_act_one_to_awaiting_act_three_input_extra_bytes() { + let test_ctx = TestCtx::new(); + let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); + act1.extend_from_slice(&[1]); + + assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(Act::Two(_)), AwaitingActThree2(_))); + } + + // Responder::AwaitingActOne -> Error (bad version byte) + #[test] + fn awaiting_act_one_to_awaiting_act_three_input_bad_version() { + let test_ctx = TestCtx::new(); + let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); + // set version byte to 1 + act1[0] = 1; + + assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("unexpected version"))); + } + + // Responder::AwaitingActOne -> Error (invalid hmac) + #[test] + fn awaiting_act_one_to_awaiting_act_three_invalid_hmac() { + let test_ctx = TestCtx::new(); + // Modify the initiator to point to a different responder + let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); + // corrupt the ciphertext + act1[34] = 0; + + assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("invalid hmac"))); + } + + // Responder::AwaitingActOne -> Error (invalid remote ephemeral key) + #[test] + fn awaiting_act_one_to_awaiting_act_three_invalid_remote_ephemeral_key() { + let test_ctx = TestCtx::new(); + // Modify the initiator to point to a different responder + let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); + // corrupt the ephemeral public key + act1[1] = 0; + + assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("invalid remote ephemeral public key"))); + } + + // Responder::AwaitingActOne -> AwaitingActThree + #[test] + fn awaiting_act_one_to_awaiting_act_three() { + let test_ctx = TestCtx::new(); + let (act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); + + assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(Act::Two(_)), AwaitingActThree2(_))); + } + + // Initiator::AwaitingActTwo -> Complete + #[test] + fn awaiting_act_two_to_complete() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + + let remote_pubkey = if let (Some(Act::Three(_)), Complete2(Some((_, remote_pubkey)))) = awaiting_act_two_state.next(&act2).unwrap() { + remote_pubkey + } else { + panic!(); + }; + + assert_eq!(remote_pubkey, test_ctx.responder_public_key); + } + + // Initiator::AwaitingActTwo -> Complete (with extra data) + // Ensures that any remaining data in the read buffer is transferred to the conduit once + // the handshake is complete + // TODO: Is this valid? Don't we expect peers to need ActThree before sending additional data? + #[test] + fn awaiting_act_two_to_complete_excess_bytes_are_in_conduit() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + act2.extend_from_slice(&[1; 100]); + + let (_act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + + let conduit = if let Complete2(Some((conduit, _))) = complete_state { + conduit + } else { + panic!(); + }; + + assert_eq!(100, conduit.decryptor.read_buffer_length()); + } + + // Initiator::AwaitingActTwo -> Error (input too small) + #[test] + fn awaiting_act_two_input_too_small() { + let test_ctx = TestCtx::new(); + let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + + assert_eq!(awaiting_act_two_state.next(&[]).err(), Some(String::from("need at least 50 bytes"))); + } + + // Initiator::AwaitingActTwo -> Error (bad version byte) + #[test] + fn awaiting_act_two_bad_version_byte() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + // set invalid version byte + act2[0] = 1; + + assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("unexpected version"))); + } + + // Initiator::AwaitingActTwo -> Error (invalid hmac) + #[test] + fn awaiting_act_two_invalid_hmac() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + // corrupt the ciphertext + act2[34] = 0; + + assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("invalid hmac"))); + } + + // Initiator::AwaitingActTwo -> Error (invalid ephemeral public key) + #[test] + fn awaiting_act_two_invalid_ephemeral_public_key() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + // corrupt the ephemeral public key + act2[1] = 0; + + assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("invalid remote ephemeral public key"))); + } + + // Responder::AwaitingActThree -> Complete + #[test] + fn awaiting_act_three_to_complete() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + + let remote_pubkey = if let (None, Complete2(Some((_, remote_pubkey)))) = awaiting_act_three_state.next(&act3).unwrap() { + remote_pubkey + } else { + panic!(); + }; + + assert_eq!(remote_pubkey, test_ctx.initiator_public_key); + } + + // Responder::AwaitingActThree -> None (with extra bytes) + // Ensures that any remaining data in the read buffer is transferred to the conduit once + // the handshake is complete + #[test] + fn awaiting_act_three_excess_bytes_after_complete_are_in_conduit() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + act3.extend_from_slice(&[2; 100]); + + let conduit = if let (_, Complete2(Some((conduit, _)))) = awaiting_act_three_state.next(&act3).unwrap() { + conduit + } else { + panic!(); + }; + + assert_eq!(100, conduit.decryptor.read_buffer_length()); + } + + // Responder::AwaitingActThree -> Error (input too small) + #[test] + fn awaiting_act_three_input_too_small() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (act3, _complete) = do_next_or_panic!(awaiting_act_two_state, &act2); + + assert_eq!(awaiting_act_three_state.next(&act3[..65]).err(), Some(String::from("need at least 66 bytes"))); + } + + // Responder::AwaitingActThree -> Error (bad version bytes) + #[test] + fn awaiting_act_three_bad_version_bytes() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + // set version byte to 1 + act3[0] = 1; + + assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("unexpected version"))); + } + + // Responder::AwaitingActThree -> Error (invalid hmac) + #[test] + fn awaiting_act_three_invalid_hmac() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + // corrupt encrypted pubkey + act3[1] = 1; + + assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("invalid hmac"))); + } + + // Responder::AwaitingActThree -> Error (invalid tag hmac) + #[test] + fn awaiting_act_three_invalid_tag_hmac() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + // corrupt tag + act3[50] = 1; + + assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("invalid hmac"))); + } + + // Initiator::Complete -> Error + #[test] + #[should_panic(expected = "no acts left to process")] + fn initiator_complete_next_fail() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (_act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + + complete_state.next(&[]).unwrap(); + } + + // Initiator::Complete -> Error + #[test] + #[should_panic(expected = "no acts left to process")] + fn responder_complete_next_fail() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + + let complete_state = if let (None, complete_state) = awaiting_act_three_state.next(&act3).unwrap() { + complete_state + } else { + panic!(); + }; + + complete_state.next(&[]).unwrap(); + } + + // Test the Act byte generation against known good hard-coded values in case the implementation + // changes in a symmetric way that makes the other tests useless + #[test] + fn test_acts_against_reference_bytes() { + let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + + assert_eq!(hex::encode(&act1), + "00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a"); + assert_eq!(hex::encode(&act2), + "0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae"); + assert_eq!(hex::encode(&act3), + "00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"); + } +} From 55ad1c70f7c9b9cbc2d33ae8268971c90b8947f4 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 18 Aug 2020 20:13:39 -0700 Subject: [PATCH 31/96] refactor: Use new state machine in PeerHandshake PeerHandshake is now a simple object around the new state machine that simply marshals data between the callers and state machine states. For now, keep the APIs identical to make the patches easier to read. The only interesting piece to note here is the handling of get_remote_pubkey() to keep parity with the existing implementation. Future patches will remove this separate function in favor of callers taking ownership of it once the handshake is complete. --- lightning/src/ln/peers/handshake/mod.rs | 285 +++------------------ lightning/src/ln/peers/handshake/states.rs | 28 -- 2 files changed, 30 insertions(+), 283 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index babdb32129b..987af5339af 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -10,9 +10,9 @@ use bitcoin::secp256k1::{PublicKey, SecretKey}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; -use ln::peers::handshake::acts::{ActOne, ActThree, ActTwo, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, Act}; +use ln::peers::handshake::acts::Act; use ln::peers::handshake::hash::HandshakeHash; -use ln::peers::handshake::states::{ActOneExpectation, ActThreeExpectation, ActTwoExpectation, HandshakeState}; +use ln::peers::handshake::states::{HandshakeState2, UninitiatedHandshakeState, AwaitingActOneHandshakeState}; mod acts; mod hash; @@ -21,42 +21,25 @@ mod states; /// Object for managing handshakes. /// Currently requires explicit ephemeral private key specification. pub struct PeerHandshake { - state: Option, - private_key: SecretKey, + state: Option, remote_public_key: Option, - ephemeral_private_key: SecretKey, - - read_buffer: Vec, } impl PeerHandshake { /// Instantiate a new handshake with a node identity secret key and an ephemeral private key pub fn new_outbound(private_key: &SecretKey, remote_public_key: &PublicKey, ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState::Uninitiated), - private_key: (*private_key).clone(), + state: Some(HandshakeState2::Uninitiated2(UninitiatedHandshakeState::new(private_key.clone(), ephemeral_private_key.clone(), remote_public_key.clone()))), remote_public_key: Some(remote_public_key.clone()), - ephemeral_private_key: (*ephemeral_private_key).clone(), - read_buffer: Vec::new(), } } /// Instantiate a new handshake in anticipation of a peer's first handshake act pub fn new_inbound(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { - let mut handshake = Self { - state: Some(HandshakeState::Uninitiated), - private_key: (*private_key).clone(), + Self { + state: Some(HandshakeState2::AwaitingActOne2(AwaitingActOneHandshakeState::new(private_key.clone(), ephemeral_private_key.clone()))), remote_public_key: None, - ephemeral_private_key: (*ephemeral_private_key).clone(), - read_buffer: Vec::new(), - }; - let public_key = Self::private_key_to_public_key(&private_key); - let (hash, chaining_key) = Self::initialize_state(&public_key); - handshake.state = Some(HandshakeState::AwaitingActOne(ActOneExpectation { - hash, - chaining_key, - })); - handshake + } } /// Return the remote public key once it has been extracted from the third act. @@ -91,231 +74,23 @@ impl PeerHandshake { /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Conduit option if the handshake was just processed to completion and messages can now be encrypted and decrypted pub fn process_act(&mut self, input: &[u8]) -> Result<(Option, Option), String> { - let mut response = None; - let mut connected_peer = None; - - self.read_buffer.extend_from_slice(input); - let read_buffer_length = self.read_buffer.len(); - - match &self.state { - &Some(HandshakeState::Uninitiated) => { - let remote_public_key = &self.remote_public_key.ok_or("outbound connections must be initialized with new_outbound")?; - let act_one = self.initiate(&remote_public_key)?; - response = Some(Act::One(act_one)); - } - &Some(HandshakeState::AwaitingActOne(_)) => { - if read_buffer_length < ACT_ONE_LENGTH { - return Err("need at least 50 bytes".to_string()); - } - - let mut act_one_buffer = [0u8; ACT_ONE_LENGTH]; - act_one_buffer.copy_from_slice(&self.read_buffer[..ACT_ONE_LENGTH]); - self.read_buffer.drain(..ACT_ONE_LENGTH); - - let act_two = self.process_act_one(ActOne(act_one_buffer))?; - response = Some(Act::Two(act_two)); - } - &Some(HandshakeState::AwaitingActTwo(_)) => { - if read_buffer_length < ACT_TWO_LENGTH { - return Err("need at least 50 bytes".to_string()); - } - - let mut act_two_buffer = [0u8; ACT_TWO_LENGTH]; - act_two_buffer.copy_from_slice(&self.read_buffer[..ACT_TWO_LENGTH]); - self.read_buffer.drain(..ACT_TWO_LENGTH); - - let (act_three, mut conduit) = self.process_act_two(ActTwo(act_two_buffer))?; - - if self.read_buffer.len() > 0 { // have we received more data still? - conduit.read(&self.read_buffer[..]); - self.read_buffer.drain(..); - } - - response = Some(Act::Three(act_three)); - connected_peer = Some(conduit); - } - &Some(HandshakeState::AwaitingActThree(_)) => { - if read_buffer_length < ACT_THREE_LENGTH { - return Err("need at least 66 bytes".to_string()); - } - - let mut act_three_buffer = [0u8; ACT_THREE_LENGTH]; - act_three_buffer.copy_from_slice(&self.read_buffer[..ACT_THREE_LENGTH]); - self.read_buffer.drain(..ACT_THREE_LENGTH); - - let (public_key, mut conduit) = self.process_act_three(ActThree(act_three_buffer))?; - - if self.read_buffer.len() > 0 { // have we received more data still? - conduit.read(&self.read_buffer[..]); - self.read_buffer.drain(..); - } - - connected_peer = Some(conduit); - self.remote_public_key = Some(public_key); - } - _ => { - panic!("no acts left to process"); - } - }; - Ok((response, connected_peer)) - } - - /// Initiate the handshake with a peer and return the first act - fn initiate(&mut self, remote_public_key: &PublicKey) -> Result { - if let &Some(HandshakeState::Uninitiated) = &self.state {} else { - return Err("Handshakes can only be initiated from the uninitiated state".to_string()); - } - - let (mut hash, chaining_key) = Self::initialize_state(&remote_public_key); - - // serialize act one - let (act_one, chaining_key, temporary_key) = Self::calculate_act_message( - &self.ephemeral_private_key, - remote_public_key, - chaining_key, - &mut hash, - ); - - self.state = Some(HandshakeState::AwaitingActTwo(ActTwoExpectation { - hash, - chaining_key, - temporary_key, - ephemeral_private_key: (*&self.ephemeral_private_key).clone(), - })); - - Ok(ActOne(act_one)) - } - - /// Process a peer's incoming first act and return the second act - fn process_act_one(&mut self, act: ActOne) -> Result { - let state = self.state.take(); - let act_one_expectation = match state { - Some(HandshakeState::AwaitingActOne(act_state)) => act_state, - Some(HandshakeState::Uninitiated) => { - let public_key = Self::private_key_to_public_key(&self.private_key); - let (hash, chaining_key) = Self::initialize_state(&public_key); - ActOneExpectation { - hash, - chaining_key, - } - } - _ => { - self.state = state; - panic!("unexpected state"); - } - }; - - let mut hash = act_one_expectation.hash; - let (remote_ephemeral_public_key, chaining_key, _) = Self::process_act_message( - act.0, - &self.private_key, - act_one_expectation.chaining_key, - &mut hash, - )?; - - let ephemeral_private_key = (*&self.ephemeral_private_key).clone(); - - let (act_two, chaining_key, temporary_key) = Self::calculate_act_message( - &ephemeral_private_key, - &remote_ephemeral_public_key, - chaining_key, - &mut hash, - ); - - self.state = Some(HandshakeState::AwaitingActThree(ActThreeExpectation { - hash, - chaining_key, - temporary_key, - ephemeral_private_key, - remote_ephemeral_public_key, - })); - - Ok(ActTwo(act_two)) - } - - /// Process a peer's incoming second act and return the third act alongside a Conduit instance - fn process_act_two(&mut self, act: ActTwo) -> Result<(ActThree, Conduit), String> { - let state = self.state.take(); - let act_two_expectation = match state { - Some(HandshakeState::AwaitingActTwo(act_state)) => act_state, - _ => { - self.state = state; - panic!("unexpected state".to_string()); - } - }; - - let mut hash = act_two_expectation.hash; - let (remote_ephemeral_public_key, chaining_key, temporary_key) = Self::process_act_message( - act.0, - &act_two_expectation.ephemeral_private_key, - act_two_expectation.chaining_key, - &mut hash, - )?; - - self.state = Some(HandshakeState::Complete); - - // start serializing act three - - let static_public_key = Self::private_key_to_public_key(&self.private_key); - let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &static_public_key.serialize()); - hash.update(&tagged_encrypted_pubkey); - - let ecdh = Self::ecdh(&self.private_key, &remote_ephemeral_public_key); - let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); - let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); - - let mut act_three = [0u8; ACT_THREE_LENGTH]; - act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); - act_three[50..].copy_from_slice(authentication_tag.as_slice()); - - let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key); - Ok((ActThree(act_three), connected_peer)) - } - - /// Process a peer's incoming third act and return a Conduit instance - fn process_act_three(&mut self, act: ActThree) -> Result<(PublicKey, Conduit), String> { - let state = self.state.take(); - let act_three_expectation = match state { - Some(HandshakeState::AwaitingActThree(act_state)) => act_state, - _ => { - self.state = state; - panic!("unexpected state".to_string()); - } - }; - - let version = act.0[0]; - if version != 0 { - // this should not crash the process, hence no panic - return Err("unexpected version".to_string()); - } + let cur_state = self.state.take().unwrap(); - let mut tagged_encrypted_pubkey = [0u8; 49]; - tagged_encrypted_pubkey.copy_from_slice(&act.0[1..50]); + let (act_opt, mut next_state) = cur_state.next(input)?; - let mut chacha_tag = [0u8; 16]; - chacha_tag.copy_from_slice(&act.0[50..66]); - - let mut hash = act_three_expectation.hash; + let result = match next_state { + HandshakeState2::Complete2(ref mut conduit_and_pubkey) => { + let (conduit, remote_pubkey) = conduit_and_pubkey.take().unwrap(); + self.remote_public_key = Some(remote_pubkey); - let remote_pubkey_vec = chacha::decrypt(&act_three_expectation.temporary_key, 1, &hash.value, &tagged_encrypted_pubkey)?; - let mut remote_pubkey_bytes = [0u8; 33]; - remote_pubkey_bytes.copy_from_slice(remote_pubkey_vec.as_slice()); - let remote_pubkey = if let Ok(public_key) = PublicKey::from_slice(&remote_pubkey_bytes) { - public_key - } else { - return Err("invalid remote public key".to_string()); + Ok((act_opt, Some(conduit))) + }, + _ => { Ok((act_opt, None)) } }; - hash.update(&tagged_encrypted_pubkey); + self.state = Some(next_state); - let ecdh = Self::ecdh(&act_three_expectation.ephemeral_private_key, &remote_pubkey); - let (chaining_key, temporary_key) = hkdf::derive(&act_three_expectation.chaining_key, &ecdh); - let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; - let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); - - let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key); - Ok((remote_pubkey, connected_peer)) + result } fn calculate_act_message(local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { @@ -401,7 +176,7 @@ mod test { use ln::peers::handshake::PeerHandshake; use ln::peers::handshake::acts::Act; - use ln::peers::handshake::states::HandshakeState; + use ln::peers::handshake::states::HandshakeState2; struct TestCtx { outbound_handshake: PeerHandshake, @@ -454,7 +229,7 @@ mod test { fn peer_handshake_new_outbound() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::Uninitiated)); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::Uninitiated2(_))); assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } @@ -463,7 +238,7 @@ mod test { fn peer_handshake_new_inbound() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::AwaitingActOne(_))); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActOne2(_))); assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } @@ -477,7 +252,7 @@ mod test { let mut test_ctx = TestCtx::new(); assert_matches!(test_ctx.outbound_handshake.process_act(&[]).unwrap(), (Some(Act::One(_)), None)); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::AwaitingActTwo(_))); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } @@ -488,7 +263,7 @@ mod test { // TODO: process_act() should error if state does not use vec, but it is non-empty assert_matches!(test_ctx.outbound_handshake.process_act(&[1]).unwrap(), (Some(Act::One(_)), None)); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::AwaitingActTwo(_))); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } @@ -509,7 +284,7 @@ mod test { act1.extend_from_slice(&[1]); assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(Act::Two(_)), None)); - assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::AwaitingActThree(_))); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } @@ -553,8 +328,8 @@ mod test { let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(Act::Two(_)), None)); - assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::AwaitingActThree(_))); - assert_eq!(test_ctx.inbound_handshake.get_remote_pubkey(), None); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); + assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } // Outbound::AwaitingActTwo -> Complete (valid conduit) @@ -565,7 +340,7 @@ mod test { let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); assert_matches!(test_ctx.outbound_handshake.process_act(&act2).unwrap(), (Some(Act::Three(_)), Some(_))); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::Complete)); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::Complete2(_))); assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } @@ -636,8 +411,7 @@ mod test { assert_eq!(test_ctx.outbound_handshake.process_act(&act2).err(), Some(String::from("invalid remote ephemeral public key"))); } - // Inbound::AwaitingActThree -> None - // TODO: should this transition to Complete instead of None? + // Inbound::AwaitingActThree -> Complete #[test] fn peer_handshake_new_inbound_awaiting_act_three_to_awaiting_act_three() { let mut test_ctx = TestCtx::new(); @@ -646,10 +420,11 @@ mod test { let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); assert_matches!(test_ctx.inbound_handshake.process_act(&act3).unwrap(), (None, Some(_))); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::Complete2(_))); assert_eq!(test_ctx.inbound_handshake.get_remote_pubkey(), Some(test_ctx.outbound_public_key)); } - // Inbound::AwaitingActThree -> None (with extra bytes) + // Inbound::AwaitingActThree -> Complete (with extra bytes) // Ensures that any remaining data in the read buffer is transferred to the conduit once // the handshake is complete #[test] diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 3f2649bfdd8..b682d69930d 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -9,14 +9,6 @@ use ln::peers::handshake::PeerHandshake; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::Conduit; -pub enum HandshakeState { - Uninitiated, - AwaitingActOne(ActOneExpectation), - AwaitingActTwo(ActTwoExpectation), - AwaitingActThree(ActThreeExpectation), - Complete, -} - pub enum HandshakeState2 { Uninitiated2(UninitiatedHandshakeState), AwaitingActOne2(AwaitingActOneHandshakeState), @@ -309,26 +301,6 @@ impl AwaitingActThreeHandshakeState { } } -pub struct ActOneExpectation { - pub(super) hash: HandshakeHash, - pub(super) chaining_key: [u8; 32], -} - -pub struct ActTwoExpectation { - pub(super) hash: HandshakeHash, - pub(super) chaining_key: [u8; 32], - pub(super) temporary_key: [u8; 32], - pub(super) ephemeral_private_key: SecretKey, -} - -pub struct ActThreeExpectation { - pub(super) hash: HandshakeHash, - pub(super) chaining_key: [u8; 32], - pub(super) temporary_key: [u8; 32], - pub(super) ephemeral_private_key: SecretKey, - pub(super) remote_ephemeral_public_key: PublicKey, -} - #[cfg(test)] mod test { use hex; From 6b2db7f4c332b39342f75569cb4e35f21a0dbb56 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 13:07:03 -0700 Subject: [PATCH 32/96] refactor: Move helper functions to the states.rs --- lightning/src/ln/peers/handshake/mod.rs | 98 +----------------- lightning/src/ln/peers/handshake/states.rs | 111 +++++++++++++++++++-- 2 files changed, 102 insertions(+), 107 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 987af5339af..d2eb122c7c2 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -2,16 +2,10 @@ //! Handshake states can be advanced automatically, or by manually calling the appropriate step. //! Once complete, returns an instance of Conduit. -use bitcoin::secp256k1; - -use bitcoin::hashes::{Hash, HashEngine}; -use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{PublicKey, SecretKey}; -use ln::peers::{chacha, hkdf}; -use ln::peers::conduit::{Conduit, SymmetricKey}; +use ln::peers::conduit::Conduit; use ln::peers::handshake::acts::Act; -use ln::peers::handshake::hash::HandshakeHash; use ln::peers::handshake::states::{HandshakeState2, UninitiatedHandshakeState, AwaitingActOneHandshakeState}; mod acts; @@ -48,23 +42,6 @@ impl PeerHandshake { self.remote_public_key } - fn initialize_state(public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { - let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; - let prologue = b"lightning"; - - let mut sha = Sha256::engine(); - sha.input(protocol_name); - let chaining_key = Sha256::from_engine(sha).into_inner(); - - let mut initial_hash_preimage = chaining_key.to_vec(); - initial_hash_preimage.extend_from_slice(prologue.as_ref()); - - let mut hash = HandshakeHash::new(initial_hash_preimage.as_slice()); - hash.update(&public_key.serialize()); - - (hash, chaining_key) - } - /// Process act dynamically /// # Arguments /// `input`: Byte slice received from peer as part of the handshake protocol @@ -92,79 +69,6 @@ impl PeerHandshake { result } - - fn calculate_act_message(local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { - let local_public_key = Self::private_key_to_public_key(local_private_key); - - hash.update(&local_public_key.serialize()); - - let ecdh = Self::ecdh(local_private_key, &remote_public_key); - let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); - - hash.update(&tagged_ciphertext); - - let mut act = [0u8; 50]; - act[1..34].copy_from_slice(&local_public_key.serialize()); - act[34..].copy_from_slice(tagged_ciphertext.as_slice()); - - (act, chaining_key, temporary_key) - } - - // Due to the very high similarity of acts 1 and 2, this method is used to process both - fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { - let version = act_bytes[0]; - if version != 0 { - // this should not crash the process, hence no panic - return Err("unexpected version".to_string()); - } - - let mut ephemeral_public_key_bytes = [0u8; 33]; - ephemeral_public_key_bytes.copy_from_slice(&act_bytes[1..34]); - let ephemeral_public_key = if let Ok(public_key) = PublicKey::from_slice(&ephemeral_public_key_bytes) { - public_key - } else { - return Err("invalid remote ephemeral public key".to_string()); - }; - - let mut chacha_tag = [0u8; 16]; - chacha_tag.copy_from_slice(&act_bytes[34..50]); - - // process the act message - - // update hash with partner's pubkey - hash.update(&ephemeral_public_key.serialize()); - - // calculate ECDH with partner's pubkey and local privkey - let ecdh = Self::ecdh(local_private_key, &ephemeral_public_key); - - // HKDF(chaining key, ECDH) -> chaining key' + next temporary key - let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - - // Validate chacha tag (temporary key, 0, hash, chacha_tag) - let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; - - hash.update(&chacha_tag); - - Ok((ephemeral_public_key, chaining_key, temporary_key)) - } - - fn private_key_to_public_key(private_key: &SecretKey) -> PublicKey { - let curve = secp256k1::Secp256k1::new(); - let pk_object = PublicKey::from_secret_key(&curve, &private_key); - pk_object - } - - fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> SymmetricKey { - let curve = secp256k1::Secp256k1::new(); - let mut pk_object = public_key.clone(); - pk_object.mul_assign(&curve, &private_key[..]).expect("invalid multiplication"); - - let preimage = pk_object.serialize(); - let mut sha = Sha256::engine(); - sha.input(preimage.as_ref()); - Sha256::from_engine(sha).into_inner() - } } #[cfg(test)] diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index b682d69930d..de2a225cb15 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -1,13 +1,14 @@ use bitcoin::secp256k1; +use bitcoin::hashes::{Hash, HashEngine}; +use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::handshake::hash::HandshakeHash; use ln::peers::handshake::acts::{Act, ActOne, ACT_ONE_LENGTH, ActTwo, ACT_TWO_LENGTH, ACT_THREE_LENGTH, ActThree}; use ln::peers::handshake::states::HandshakeState2::{AwaitingActTwo2, AwaitingActThree2, Complete2}; -use ln::peers::handshake::PeerHandshake; use ln::peers::{chacha, hkdf}; -use ln::peers::conduit::Conduit; +use ln::peers::conduit::{Conduit, SymmetricKey}; pub enum HandshakeState2 { Uninitiated2(UninitiatedHandshakeState), @@ -81,10 +82,10 @@ impl IHandshakeState for UninitiatedHandshakeState { let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; let responder_public_key = self.responder_public_key; - let (mut hash, chaining_key) = PeerHandshake::initialize_state(&responder_public_key); + let (mut hash, chaining_key) = initialize_state(&responder_public_key); // serialize act one - let (act_one, chaining_key, _) = PeerHandshake::calculate_act_message( + let (act_one, chaining_key, _) = calculate_act_message( &initiator_ephemeral_private_key, &responder_public_key, chaining_key, @@ -103,7 +104,7 @@ impl AwaitingActOneHandshakeState { let curve = secp256k1::Secp256k1::new(); let responder_public_key = PublicKey::from_secret_key(&curve, &responder_private_key); - let (hash, chaining_key) = PeerHandshake::initialize_state(&responder_public_key); + let (hash, chaining_key) = initialize_state(&responder_public_key); AwaitingActOneHandshakeState { responder_private_key, @@ -135,14 +136,14 @@ impl IHandshakeState for AwaitingActOneHandshakeState { act_one_bytes.copy_from_slice(&read_buffer[..ACT_ONE_LENGTH]); read_buffer.drain(..ACT_ONE_LENGTH); - let (initiator_ephemeral_public_key, chaining_key, _) = PeerHandshake::process_act_message( + let (initiator_ephemeral_public_key, chaining_key, _) = process_act_message( act_one_bytes, &responder_private_key, chaining_key, &mut hash, )?; - let (act_two, chaining_key, temporary_key) = PeerHandshake::calculate_act_message( + let (act_two, chaining_key, temporary_key) = calculate_act_message( &responder_ephemeral_private_key, &initiator_ephemeral_public_key, chaining_key, @@ -179,7 +180,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { act_two_bytes.copy_from_slice(&read_buffer[..ACT_TWO_LENGTH]); read_buffer.drain(..ACT_TWO_LENGTH); - let (responder_ephemeral_public_key, chaining_key, temporary_key) = PeerHandshake::process_act_message( + let (responder_ephemeral_public_key, chaining_key, temporary_key) = process_act_message( act_two_bytes, &initiator_ephemeral_private_key, chaining_key, @@ -193,7 +194,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_public_key.serialize()); hash.update(&tagged_encrypted_pubkey); - let ecdh = PeerHandshake::ecdh(&initiator_private_key, &responder_ephemeral_public_key); + let ecdh = ecdh(&initiator_private_key, &responder_ephemeral_public_key); let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); @@ -270,7 +271,7 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { hash.update(&tagged_encrypted_pubkey); - let ecdh = PeerHandshake::ecdh(&responder_ephemeral_private_key, &initiator_pubkey); + let ecdh = ecdh(&responder_ephemeral_private_key, &initiator_pubkey); let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); @@ -301,6 +302,96 @@ impl AwaitingActThreeHandshakeState { } } +fn initialize_state(public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { + let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; + let prologue = b"lightning"; + + let mut sha = Sha256::engine(); + sha.input(protocol_name); + let chaining_key = Sha256::from_engine(sha).into_inner(); + + let mut initial_hash_preimage = chaining_key.to_vec(); + initial_hash_preimage.extend_from_slice(prologue.as_ref()); + + let mut hash = HandshakeHash::new(initial_hash_preimage.as_slice()); + hash.update(&public_key.serialize()); + + (hash, chaining_key) +} + +fn calculate_act_message(local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { + let local_public_key = private_key_to_public_key(local_private_key); + + hash.update(&local_public_key.serialize()); + + let ecdh = ecdh(local_private_key, &remote_public_key); + let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); + + hash.update(&tagged_ciphertext); + + let mut act = [0u8; 50]; + act[1..34].copy_from_slice(&local_public_key.serialize()); + act[34..].copy_from_slice(tagged_ciphertext.as_slice()); + + (act, chaining_key, temporary_key) +} + +// Due to the very high similarity of acts 1 and 2, this method is used to process both +fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { + let version = act_bytes[0]; + if version != 0 { + // this should not crash the process, hence no panic + return Err("unexpected version".to_string()); + } + + let mut ephemeral_public_key_bytes = [0u8; 33]; + ephemeral_public_key_bytes.copy_from_slice(&act_bytes[1..34]); + let ephemeral_public_key = if let Ok(public_key) = PublicKey::from_slice(&ephemeral_public_key_bytes) { + public_key + } else { + return Err("invalid remote ephemeral public key".to_string()); + }; + + let mut chacha_tag = [0u8; 16]; + chacha_tag.copy_from_slice(&act_bytes[34..50]); + + // process the act message + + // update hash with partner's pubkey + hash.update(&ephemeral_public_key.serialize()); + + // calculate ECDH with partner's pubkey and local privkey + let ecdh = ecdh(local_private_key, &ephemeral_public_key); + + // HKDF(chaining key, ECDH) -> chaining key' + next temporary key + let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + + // Validate chacha tag (temporary key, 0, hash, chacha_tag) + let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; + + hash.update(&chacha_tag); + + Ok((ephemeral_public_key, chaining_key, temporary_key)) +} + +fn private_key_to_public_key(private_key: &SecretKey) -> PublicKey { + let curve = secp256k1::Secp256k1::new(); + let pk_object = PublicKey::from_secret_key(&curve, &private_key); + pk_object +} + +fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> SymmetricKey { + let curve = secp256k1::Secp256k1::new(); + let mut pk_object = public_key.clone(); + pk_object.mul_assign(&curve, &private_key[..]).expect("invalid multiplication"); + + let preimage = pk_object.serialize(); + let mut sha = Sha256::engine(); + sha.input(preimage.as_ref()); + Sha256::from_engine(sha).into_inner() +} + #[cfg(test)] mod test { use hex; From 42138cf341fe319b8c6c284a54d661d1a76ca77a Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 16:14:53 -0700 Subject: [PATCH 33/96] refactor: Structure initialize_state based on RFC Introduce the sha256!() and concat!() macros that are used to improve readability of the noise exchanges. --- lightning/src/ln/peers/handshake/states.rs | 45 +++++++++++++++++----- 1 file changed, 35 insertions(+), 10 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index de2a225cb15..1a19c2f34ad 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -82,7 +82,7 @@ impl IHandshakeState for UninitiatedHandshakeState { let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; let responder_public_key = self.responder_public_key; - let (mut hash, chaining_key) = initialize_state(&responder_public_key); + let (mut hash, chaining_key) = handshake_state_initialization(&responder_public_key); // serialize act one let (act_one, chaining_key, _) = calculate_act_message( @@ -104,7 +104,7 @@ impl AwaitingActOneHandshakeState { let curve = secp256k1::Secp256k1::new(); let responder_public_key = PublicKey::from_secret_key(&curve, &responder_private_key); - let (hash, chaining_key) = initialize_state(&responder_public_key); + let (hash, chaining_key) = handshake_state_initialization(&responder_public_key); AwaitingActOneHandshakeState { responder_private_key, @@ -302,19 +302,44 @@ impl AwaitingActThreeHandshakeState { } } -fn initialize_state(public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { +// Generate a SHA-256 hash from one or more elements +macro_rules! sha256 { + ( $( $x:expr ),+ ) => {{ + let mut sha = Sha256::engine(); + $( + sha.input($x.as_ref()); + )* + Sha256::from_engine(sha).into_inner() + }} +} + +// Concatenate two slices in a Vec +macro_rules! concat { + ($arg1:expr, $arg2:expr) => {{ + let mut result = $arg1.to_vec(); + result.extend_from_slice($arg2.as_ref()); + result + }} +} + +// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization +fn handshake_state_initialization(responder_public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; let prologue = b"lightning"; - let mut sha = Sha256::engine(); - sha.input(protocol_name); - let chaining_key = Sha256::from_engine(sha).into_inner(); + // 1. h = SHA-256(protocolName) + // 2. ck = h + let chaining_key = sha256!(protocol_name); + + // 3. h = SHA-256(h || prologue) + let hash = sha256!(concat!(chaining_key, prologue)); - let mut initial_hash_preimage = chaining_key.to_vec(); - initial_hash_preimage.extend_from_slice(prologue.as_ref()); + // h = SHA-256(h || responderPublicKey) + let hash = sha256!(concat!(hash, responder_public_key.serialize())); - let mut hash = HandshakeHash::new(initial_hash_preimage.as_slice()); - hash.update(&public_key.serialize()); + let hash = HandshakeHash { + value: hash + }; (hash, chaining_key) } From 0dfc9668f15947211d6fdd48b4e983d084cedce0 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 16:49:21 -0700 Subject: [PATCH 34/96] refactor: Structure calculate_act_message based on RFC Small inconvenience with the HandshakeHash return value that will be taken care of by the end of this patch stack. --- lightning/src/ln/peers/handshake/states.rs | 33 ++++++++++++++++------ 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 1a19c2f34ad..61129d14791 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -344,19 +344,34 @@ fn handshake_state_initialization(responder_public_key: &PublicKey) -> (Handshak (hash, chaining_key) } -fn calculate_act_message(local_private_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { - let local_public_key = private_key_to_public_key(local_private_key); - - hash.update(&local_public_key.serialize()); - - let ecdh = ecdh(local_private_key, &remote_public_key); +// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) +// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) +fn calculate_act_message(local_private_ephemeral_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], h_hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { + // 1. e = generateKey() (passed in) + // 2. h = SHA-256(h || e.pub.serializeCompressed()) + let serialized_local_public_key = private_key_to_public_key(local_private_ephemeral_key).serialize(); + let hash = sha256!(concat!(h_hash.value, serialized_local_public_key)); + + // 3. ACT1: es = ECDH(e.priv, rs) + // 3. ACT2: es = ECDH(e.priv, re) + let ecdh = ecdh(local_private_ephemeral_key, &remote_public_key); + + // 4. ACT1: ck, temp_k1 = HKDF(ck, es) + // 4. ACT2: ck, temp_k2 = HKDF(ck, ee) let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); - hash.update(&tagged_ciphertext); + // 5. ACT1: c = encryptWithAD(temp_k1, 0, h, zero) + // 5. ACT2: c = encryptWithAD(temp_k2, 0, h, zero) + let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash, &[0; 0]); + + // 6. h = SHA-256(h || c) + *h_hash = HandshakeHash { + value: sha256!(hash, tagged_ciphertext) + }; + // Send m = 0 || e.pub.serializeCompressed() || c let mut act = [0u8; 50]; - act[1..34].copy_from_slice(&local_public_key.serialize()); + act[1..34].copy_from_slice(&serialized_local_public_key); act[34..].copy_from_slice(tagged_ciphertext.as_slice()); (act, chaining_key, temporary_key) From 4da51c6156c66148324d5fd56a027c76d694fbad Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 17:54:15 -0700 Subject: [PATCH 35/96] refactor: Structure process_act_message based on RFC Fix inconsistent use of concat vs. Sha256::engine() input. These can be deduplicated at the end. --- lightning/src/ln/peers/handshake/states.rs | 124 +++++++++++---------- 1 file changed, 66 insertions(+), 58 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 61129d14791..80b2e89b19d 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -35,13 +35,13 @@ trait IHandshakeState { } pub struct UninitiatedHandshakeState { - initiator_private_key: SecretKey, + initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, - responder_public_key: PublicKey, + responder_static_public_key: PublicKey, } pub struct AwaitingActOneHandshakeState { - responder_private_key: SecretKey, + responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey, chaining_key: [u8; 32], hash: HandshakeHash, @@ -49,9 +49,9 @@ pub struct AwaitingActOneHandshakeState { } pub struct AwaitingActTwoHandshakeState { - initiator_private_key: SecretKey, + initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, - responder_public_key: PublicKey, + responder_static_public_key: PublicKey, chaining_key: [u8; 32], hash: HandshakeHash, read_buffer: Vec @@ -66,48 +66,46 @@ pub struct AwaitingActThreeHandshakeState { } impl UninitiatedHandshakeState { - pub(crate) fn new(initiator_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_public_key: PublicKey) -> Self { + pub(crate) fn new(initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey) -> Self { UninitiatedHandshakeState { - initiator_private_key, + initiator_static_private_key, initiator_ephemeral_private_key, - responder_public_key + responder_static_public_key } } } impl IHandshakeState for UninitiatedHandshakeState { + // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) fn next(self, _input: &[u8]) -> Result<(Option, HandshakeState2), String> { - - let initiator_private_key = self.initiator_private_key; + let initiator_static_private_key = self.initiator_static_private_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; - let responder_public_key = self.responder_public_key; + let responder_static_public_key = self.responder_static_public_key; - let (mut hash, chaining_key) = handshake_state_initialization(&responder_public_key); + let (mut hash, chaining_key) = handshake_state_initialization(&responder_static_public_key); // serialize act one let (act_one, chaining_key, _) = calculate_act_message( &initiator_ephemeral_private_key, - &responder_public_key, + &responder_static_public_key, chaining_key, &mut hash, ); Ok(( Some(Act::One(ActOne(act_one))), - AwaitingActTwo2(AwaitingActTwoHandshakeState::new(initiator_private_key, initiator_ephemeral_private_key, responder_public_key, chaining_key, hash)) + AwaitingActTwo2(AwaitingActTwoHandshakeState::new(initiator_static_private_key, initiator_ephemeral_private_key, responder_static_public_key, chaining_key, hash)) )) } } impl AwaitingActOneHandshakeState { - pub(crate) fn new(responder_private_key: SecretKey, responder_ephemeral_private_key: SecretKey) -> Self { - - let curve = secp256k1::Secp256k1::new(); - let responder_public_key = PublicKey::from_secret_key(&curve, &responder_private_key); - let (hash, chaining_key) = handshake_state_initialization(&responder_public_key); + pub(crate) fn new(responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey) -> Self { + let responder_static_public_key = private_key_to_public_key(&responder_static_private_key); + let (hash, chaining_key) = handshake_state_initialization(&responder_static_public_key); AwaitingActOneHandshakeState { - responder_private_key, + responder_static_private_key, responder_ephemeral_private_key, chaining_key, hash, @@ -117,8 +115,9 @@ impl AwaitingActOneHandshakeState { } impl IHandshakeState for AwaitingActOneHandshakeState { + // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) + // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { - let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -127,18 +126,18 @@ impl IHandshakeState for AwaitingActOneHandshakeState { } let mut hash = self.hash; - let responder_private_key = self.responder_private_key; + let responder_static_private_key = self.responder_static_private_key; let chaining_key = self.chaining_key; let responder_ephemeral_private_key = self.responder_ephemeral_private_key; - // common functions take in an array so drain here for now + // 1. Read exactly 50 bytes from the network buffer let mut act_one_bytes = [0u8; ACT_ONE_LENGTH]; act_one_bytes.copy_from_slice(&read_buffer[..ACT_ONE_LENGTH]); read_buffer.drain(..ACT_ONE_LENGTH); let (initiator_ephemeral_public_key, chaining_key, _) = process_act_message( act_one_bytes, - &responder_private_key, + &responder_static_private_key, chaining_key, &mut hash, )?; @@ -160,8 +159,9 @@ impl IHandshakeState for AwaitingActOneHandshakeState { } impl IHandshakeState for AwaitingActTwoHandshakeState { + // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) + // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (sender) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { - let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -169,13 +169,13 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { return Err("need at least 50 bytes".to_string()); } - let initiator_private_key = self.initiator_private_key; + let initiator_static_private_key = self.initiator_static_private_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; - let responder_public_key = self.responder_public_key; + let responder_static_public_key = self.responder_static_public_key; let mut hash = self.hash; let chaining_key = self.chaining_key; - // common functions take in an array so drain here for now + // 1. Read exactly 50 bytes from the network buffer let mut act_two_bytes = [0u8; ACT_TWO_LENGTH]; act_two_bytes.copy_from_slice(&read_buffer[..ACT_TWO_LENGTH]); read_buffer.drain(..ACT_TWO_LENGTH); @@ -190,11 +190,11 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { // start serializing act three let curve = secp256k1::Secp256k1::new(); - let initiator_public_key = PublicKey::from_secret_key(&curve, &initiator_private_key); + let initiator_public_key = PublicKey::from_secret_key(&curve, &initiator_static_private_key); let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_public_key.serialize()); hash.update(&tagged_encrypted_pubkey); - let ecdh = ecdh(&initiator_private_key, &responder_ephemeral_public_key); + let ecdh = ecdh(&initiator_static_private_key, &responder_ephemeral_public_key); let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); @@ -212,17 +212,17 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { Ok(( Some(Act::Three(ActThree(act_three))), - Complete2(Some((conduit, responder_public_key))) + Complete2(Some((conduit, responder_static_public_key))) )) } } impl AwaitingActTwoHandshakeState { - fn new(initiator_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_public_key: PublicKey, chaining_key: [u8;32], hash: HandshakeHash) -> Self { + fn new(initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey, chaining_key: [u8;32], hash: HandshakeHash) -> Self { AwaitingActTwoHandshakeState { - initiator_private_key, + initiator_static_private_key, initiator_ephemeral_private_key, - responder_public_key, + responder_static_public_key, chaining_key, hash, read_buffer: Vec::new() @@ -323,7 +323,7 @@ macro_rules! concat { } // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization -fn handshake_state_initialization(responder_public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { +fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; let prologue = b"lightning"; @@ -335,7 +335,7 @@ fn handshake_state_initialization(responder_public_key: &PublicKey) -> (Handshak let hash = sha256!(concat!(chaining_key, prologue)); // h = SHA-256(h || responderPublicKey) - let hash = sha256!(concat!(hash, responder_public_key.serialize())); + let hash = sha256!(concat!(hash, responder_static_public_key.serialize())); let hash = HandshakeHash { value: hash @@ -378,12 +378,11 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, remote_public_ } // Due to the very high similarity of acts 1 and 2, this method is used to process both -fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { +// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) +// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) +fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, h_hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { + // 2.Parse the read message (m) into v, re, and c let version = act_bytes[0]; - if version != 0 { - // this should not crash the process, hence no panic - return Err("unexpected version".to_string()); - } let mut ephemeral_public_key_bytes = [0u8; 33]; ephemeral_public_key_bytes.copy_from_slice(&act_bytes[1..34]); @@ -396,21 +395,30 @@ fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chain let mut chacha_tag = [0u8; 16]; chacha_tag.copy_from_slice(&act_bytes[34..50]); - // process the act message + // 3. If v is an unrecognized handshake version, then the responder MUST abort the connection attempt + if version != 0 { + // this should not crash the process, hence no panic + return Err("unexpected version".to_string()); + } - // update hash with partner's pubkey - hash.update(&ephemeral_public_key.serialize()); + // 4. h = SHA-256(h || re.serializeCompressed()) + let hash = sha256!(concat!(h_hash.value, ephemeral_public_key_bytes)); - // calculate ECDH with partner's pubkey and local privkey + // 5. Act1: es = ECDH(s.priv, re) + // 5. Act2: ee = ECDH(e.priv, ee) let ecdh = ecdh(local_private_key, &ephemeral_public_key); - // HKDF(chaining key, ECDH) -> chaining key' + next temporary key + // 6. Act1: ck, temp_k1 = HKDF(ck, es) + // 6. Act2: ck, temp_k2 = HKDF(ck, ee) let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - // Validate chacha tag (temporary key, 0, hash, chacha_tag) - let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; + // 7. p = decryptWithAD(temp_k1, 0, h, c) + let _tag_check = chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag)?; - hash.update(&chacha_tag); + // 8. h = SHA-256(h || c) + *h_hash = HandshakeHash { + value: sha256!(concat!(hash, chacha_tag)) + }; Ok((ephemeral_public_key, chaining_key, temporary_key)) } @@ -447,28 +455,28 @@ mod test { initiator: HandshakeState2, initiator_public_key: PublicKey, responder: HandshakeState2, - responder_public_key: PublicKey + responder_static_public_key: PublicKey } impl TestCtx { fn new() -> Self { let curve = secp256k1::Secp256k1::new(); - let initiator_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); - let initiator_public_key = PublicKey::from_secret_key(&curve, &initiator_private_key); + let initiator_static_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let initiator_public_key = PublicKey::from_secret_key(&curve, &initiator_static_private_key); let initiator_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); - let responder_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); - let responder_public_key = PublicKey::from_secret_key(&curve, &responder_private_key); + let responder_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let responder_static_public_key = PublicKey::from_secret_key(&curve, &responder_static_private_key); let responder_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - let initiator = UninitiatedHandshakeState::new(initiator_private_key, initiator_ephemeral_private_key, responder_public_key); - let responder = AwaitingActOneHandshakeState::new(responder_private_key, responder_ephemeral_private_key); + let initiator = UninitiatedHandshakeState::new(initiator_static_private_key, initiator_ephemeral_private_key, responder_static_public_key); + let responder = AwaitingActOneHandshakeState::new(responder_static_private_key, responder_ephemeral_private_key); TestCtx { initiator: HandshakeState2::Uninitiated2(initiator), initiator_public_key, responder: HandshakeState2::AwaitingActOne2(responder), - responder_public_key, + responder_static_public_key, } } } @@ -586,7 +594,7 @@ mod test { panic!(); }; - assert_eq!(remote_pubkey, test_ctx.responder_public_key); + assert_eq!(remote_pubkey, test_ctx.responder_static_public_key); } // Initiator::AwaitingActTwo -> Complete (with extra data) From 70510684236d372859b1ae1a753feed289d6a4bd Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 18:07:19 -0700 Subject: [PATCH 36/96] refactor: Structure creation of Act3 based on RFC Identify potential issue regarding the invalid case where the read_buffer has data after completion. --- lightning/src/ln/peers/handshake/states.rs | 70 +++++++++++++--------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 80b2e89b19d..7f325b0d524 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -10,6 +10,26 @@ use ln::peers::handshake::states::HandshakeState2::{AwaitingActTwo2, AwaitingAct use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; +// Generate a SHA-256 hash from one or more elements +macro_rules! sha256 { + ( $( $x:expr ),+ ) => {{ + let mut sha = Sha256::engine(); + $( + sha.input($x.as_ref()); + )+ + Sha256::from_engine(sha).into_inner() + }} +} + +// Concatenate two slices in a Vec +macro_rules! concat { + ($arg1:expr, $arg2:expr) => {{ + let mut result = $arg1.to_vec(); + result.extend_from_slice($arg2.as_ref()); + result + }} +} + pub enum HandshakeState2 { Uninitiated2(UninitiatedHandshakeState), AwaitingActOne2(AwaitingActOneHandshakeState), @@ -188,24 +208,38 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { )?; // start serializing act three - - let curve = secp256k1::Secp256k1::new(); - let initiator_public_key = PublicKey::from_secret_key(&curve, &initiator_static_private_key); + // 1. c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed()) + let initiator_public_key = private_key_to_public_key(&initiator_static_private_key); let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_public_key.serialize()); - hash.update(&tagged_encrypted_pubkey); + // 2. h = SHA-256(h || c) + let hash = sha256!(concat!(hash.value, tagged_encrypted_pubkey)); + + // 3. se = ECDH(s.priv, re) let ecdh = ecdh(&initiator_static_private_key, &responder_ephemeral_public_key); + + // 4. ck, temp_k3 = HKDF(ck, se) let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash.value, &[0; 0]); + + // 5. t = encryptWithAD(temp_k3, 0, h, zero) + let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash, &[0; 0]); + + // 6. sk, rk = HKDF(ck, zero) let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); + // 7. rn = 0, sn = 0 + // - done by Conduit + let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); + + // Send m = 0 || c || t over the network buffer let mut act_three = [0u8; ACT_THREE_LENGTH]; act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); act_three[50..].copy_from_slice(authentication_tag.as_slice()); - let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); - - if read_buffer.len() > 0 { // have we received more data still? + // Any remaining data in the read buffer would be encrypted, so transfer ownership + // to the Conduit for future use. In this case, it is unlikely that any valid data + // exists, since the responder doesn't have Act3 + if read_buffer.len() > 0 { conduit.read(&read_buffer[..]); read_buffer.drain(..); } @@ -302,26 +336,6 @@ impl AwaitingActThreeHandshakeState { } } -// Generate a SHA-256 hash from one or more elements -macro_rules! sha256 { - ( $( $x:expr ),+ ) => {{ - let mut sha = Sha256::engine(); - $( - sha.input($x.as_ref()); - )* - Sha256::from_engine(sha).into_inner() - }} -} - -// Concatenate two slices in a Vec -macro_rules! concat { - ($arg1:expr, $arg2:expr) => {{ - let mut result = $arg1.to_vec(); - result.extend_from_slice($arg2.as_ref()); - result - }} -} - // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; From 2d51b981beb0a777f84c51e8340d4a2f41da9660 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 18:17:49 -0700 Subject: [PATCH 37/96] refactor: Structure receiving of Act3 data based on RFC --- lightning/src/ln/peers/handshake/states.rs | 30 +++++++++++++++++----- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 7f325b0d524..3c844d4a4b2 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -265,6 +265,7 @@ impl AwaitingActTwoHandshakeState { } impl IHandshakeState for AwaitingActThreeHandshakeState { + // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (receiver) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -278,15 +279,13 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { let responder_ephemeral_private_key = self.responder_ephemeral_private_key; let chaining_key = self.chaining_key; + // 1. Read exactly 66 bytes from the network buffer let mut act_three_bytes = [0u8; ACT_THREE_LENGTH]; act_three_bytes.copy_from_slice(&read_buffer[..ACT_THREE_LENGTH]); read_buffer.drain(..ACT_THREE_LENGTH); + // 2. Parse the read message (m) into v, c, and t let version = act_three_bytes[0]; - if version != 0 { - // this should not crash the process, hence no panic - return Err("unexpected version".to_string()); - } let mut tagged_encrypted_pubkey = [0u8; 49]; tagged_encrypted_pubkey.copy_from_slice(&act_three_bytes[1..50]); @@ -294,6 +293,13 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { let mut chacha_tag = [0u8; 16]; chacha_tag.copy_from_slice(&act_three_bytes[50..66]); + // 3. If v is an unrecognized handshake version, then the responder MUST abort the connection attempt. + if version != 0 { + // this should not crash the process, hence no panic + return Err("unexpected version".to_string()); + } + + // 4. rs = decryptWithAD(temp_k2, 1, h, c) let remote_pubkey_vec = chacha::decrypt(&temporary_key, 1, &hash.value, &tagged_encrypted_pubkey)?; let mut initiator_pubkey_bytes = [0u8; 33]; initiator_pubkey_bytes.copy_from_slice(remote_pubkey_vec.as_slice()); @@ -303,15 +309,27 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { return Err("invalid remote public key".to_string()); }; - hash.update(&tagged_encrypted_pubkey); + // 5. h = SHA-256(h || c) + let hash = sha256!(concat!(hash.value, tagged_encrypted_pubkey)); + // 6. se = ECDH(e.priv, rs) let ecdh = ecdh(&responder_ephemeral_private_key, &initiator_pubkey); + + // 7. ck, temp_k3 = HKDF(ck, se) let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - let _tag_check = chacha::decrypt(&temporary_key, 0, &hash.value, &chacha_tag)?; + + // 8. p = decryptWithAD(temp_k3, 0, h, t) + let _tag_check = chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag)?; + + // 9. rk, sk = HKDF(ck, zero) let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); + // 10. rn = 0, sn = 0 + // - done by Conduit let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); + // Any remaining data in the read buffer would be encrypted, so transfer ownership + // to the Conduit for future use. if read_buffer.len() > 0 { // have we received more data still? conduit.read(&read_buffer[..]); read_buffer.drain(..); From 14d5c22de74b31483789a5913ee625eb9e357c9a Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 18:27:29 -0700 Subject: [PATCH 38/96] refactor: Inline single use constructors --- lightning/src/ln/peers/handshake/states.rs | 44 ++++++++-------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 3c844d4a4b2..4b4504956dd 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -114,7 +114,14 @@ impl IHandshakeState for UninitiatedHandshakeState { Ok(( Some(Act::One(ActOne(act_one))), - AwaitingActTwo2(AwaitingActTwoHandshakeState::new(initiator_static_private_key, initiator_ephemeral_private_key, responder_static_public_key, chaining_key, hash)) + AwaitingActTwo2(AwaitingActTwoHandshakeState { + initiator_static_private_key, + initiator_ephemeral_private_key, + responder_static_public_key, + chaining_key, + hash, + read_buffer: Vec::new() + }) )) } } @@ -171,9 +178,13 @@ impl IHandshakeState for AwaitingActOneHandshakeState { Ok(( Some(Act::Two(ActTwo(act_two))), - AwaitingActThree2( - AwaitingActThreeHandshakeState::new(hash, responder_ephemeral_private_key, chaining_key, temporary_key, read_buffer) - ) + AwaitingActThree2(AwaitingActThreeHandshakeState { + hash, + responder_ephemeral_private_key, + chaining_key, + temporary_key, + read_buffer + }) )) } } @@ -251,19 +262,6 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { } } -impl AwaitingActTwoHandshakeState { - fn new(initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey, chaining_key: [u8;32], hash: HandshakeHash) -> Self { - AwaitingActTwoHandshakeState { - initiator_static_private_key, - initiator_ephemeral_private_key, - responder_static_public_key, - chaining_key, - hash, - read_buffer: Vec::new() - } - } -} - impl IHandshakeState for AwaitingActThreeHandshakeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (receiver) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { @@ -342,18 +340,6 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { } } -impl AwaitingActThreeHandshakeState { - fn new(hash: HandshakeHash, responder_ephemeral_private_key: SecretKey, chaining_key: [u8; 32], temporary_key: [u8; 32], read_buffer: Vec) -> Self { - AwaitingActThreeHandshakeState { - hash, - responder_ephemeral_private_key, - chaining_key, - temporary_key, - read_buffer - } - } -} - // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; From 51ecdd03c474e90d463878a50dbc5a99828672a6 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 18:46:45 -0700 Subject: [PATCH 39/96] refactor: Pull public key generation to the initial states All needed public keys are calculated during the first state and passed through as needed. Limits the call sites of private_key_to_public and makes the initial states for the initiator and responder more symmetric. --- lightning/src/ln/peers/handshake/states.rs | 35 +++++++++++++++++----- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 4b4504956dd..bfc0f093b62 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -56,13 +56,18 @@ trait IHandshakeState { pub struct UninitiatedHandshakeState { initiator_static_private_key: SecretKey, + initiator_static_public_key: PublicKey, initiator_ephemeral_private_key: SecretKey, + initiator_ephemeral_public_key: PublicKey, responder_static_public_key: PublicKey, + chaining_key: [u8; 32], + hash: HandshakeHash, } pub struct AwaitingActOneHandshakeState { responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey, + responder_ephemeral_public_key: PublicKey, chaining_key: [u8; 32], hash: HandshakeHash, read_buffer: Vec @@ -70,6 +75,7 @@ pub struct AwaitingActOneHandshakeState { pub struct AwaitingActTwoHandshakeState { initiator_static_private_key: SecretKey, + initiator_static_public_key: PublicKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey, chaining_key: [u8; 32], @@ -87,10 +93,17 @@ pub struct AwaitingActThreeHandshakeState { impl UninitiatedHandshakeState { pub(crate) fn new(initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey) -> Self { + let initiator_static_public_key = private_key_to_public_key(&initiator_static_private_key); + let (hash, chaining_key) = handshake_state_initialization(&responder_static_public_key); + let initiator_ephemeral_public_key = private_key_to_public_key(&initiator_ephemeral_private_key); UninitiatedHandshakeState { initiator_static_private_key, + initiator_static_public_key, initiator_ephemeral_private_key, - responder_static_public_key + initiator_ephemeral_public_key, + responder_static_public_key, + chaining_key, + hash } } } @@ -99,14 +112,17 @@ impl IHandshakeState for UninitiatedHandshakeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) fn next(self, _input: &[u8]) -> Result<(Option, HandshakeState2), String> { let initiator_static_private_key = self.initiator_static_private_key; + let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; + let initiator_ephemeral_public_key = self.initiator_ephemeral_public_key; let responder_static_public_key = self.responder_static_public_key; - - let (mut hash, chaining_key) = handshake_state_initialization(&responder_static_public_key); + let chaining_key = self.chaining_key; + let mut hash = self.hash; // serialize act one let (act_one, chaining_key, _) = calculate_act_message( &initiator_ephemeral_private_key, + &initiator_ephemeral_public_key, &responder_static_public_key, chaining_key, &mut hash, @@ -116,6 +132,7 @@ impl IHandshakeState for UninitiatedHandshakeState { Some(Act::One(ActOne(act_one))), AwaitingActTwo2(AwaitingActTwoHandshakeState { initiator_static_private_key, + initiator_static_public_key, initiator_ephemeral_private_key, responder_static_public_key, chaining_key, @@ -130,10 +147,12 @@ impl AwaitingActOneHandshakeState { pub(crate) fn new(responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey) -> Self { let responder_static_public_key = private_key_to_public_key(&responder_static_private_key); let (hash, chaining_key) = handshake_state_initialization(&responder_static_public_key); + let responder_ephemeral_public_key = private_key_to_public_key(&responder_ephemeral_private_key); AwaitingActOneHandshakeState { responder_static_private_key, responder_ephemeral_private_key, + responder_ephemeral_public_key, chaining_key, hash, read_buffer: Vec::new() @@ -156,6 +175,7 @@ impl IHandshakeState for AwaitingActOneHandshakeState { let responder_static_private_key = self.responder_static_private_key; let chaining_key = self.chaining_key; let responder_ephemeral_private_key = self.responder_ephemeral_private_key; + let responder_ephemeral_public_key = self.responder_ephemeral_public_key; // 1. Read exactly 50 bytes from the network buffer let mut act_one_bytes = [0u8; ACT_ONE_LENGTH]; @@ -171,6 +191,7 @@ impl IHandshakeState for AwaitingActOneHandshakeState { let (act_two, chaining_key, temporary_key) = calculate_act_message( &responder_ephemeral_private_key, + &responder_ephemeral_public_key, &initiator_ephemeral_public_key, chaining_key, &mut hash, @@ -201,6 +222,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { } let initiator_static_private_key = self.initiator_static_private_key; + let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; let responder_static_public_key = self.responder_static_public_key; let mut hash = self.hash; @@ -220,8 +242,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { // start serializing act three // 1. c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed()) - let initiator_public_key = private_key_to_public_key(&initiator_static_private_key); - let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_public_key.serialize()); + let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_static_public_key.serialize()); // 2. h = SHA-256(h || c) let hash = sha256!(concat!(hash.value, tagged_encrypted_pubkey)); @@ -364,10 +385,10 @@ fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (H // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) -fn calculate_act_message(local_private_ephemeral_key: &SecretKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], h_hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { +fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], h_hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { // 1. e = generateKey() (passed in) // 2. h = SHA-256(h || e.pub.serializeCompressed()) - let serialized_local_public_key = private_key_to_public_key(local_private_ephemeral_key).serialize(); + let serialized_local_public_key = local_public_ephemeral_key.serialize(); let hash = sha256!(concat!(h_hash.value, serialized_local_public_key)); // 3. ACT1: es = ECDH(e.priv, rs) From fadf6f6b2210d84c74abbc02b870572f235b99a5 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 19:00:32 -0700 Subject: [PATCH 40/96] refactor: Remove HandshakeHash wrapper struct Create an alias type to make the code more readable and change all usages to moves. --- lightning/src/ln/peers/handshake/hash.rs | 25 ---------- lightning/src/ln/peers/handshake/mod.rs | 1 - lightning/src/ln/peers/handshake/states.rs | 56 ++++++++++------------ 3 files changed, 25 insertions(+), 57 deletions(-) delete mode 100644 lightning/src/ln/peers/handshake/hash.rs diff --git a/lightning/src/ln/peers/handshake/hash.rs b/lightning/src/ln/peers/handshake/hash.rs deleted file mode 100644 index e7704b37e34..00000000000 --- a/lightning/src/ln/peers/handshake/hash.rs +++ /dev/null @@ -1,25 +0,0 @@ -use bitcoin::hashes::{Hash, HashEngine}; -use bitcoin::hashes::sha256::Hash as Sha256; - -pub(crate) struct HandshakeHash { - pub(super) value: [u8; 32] -} - -impl HandshakeHash { - pub(super) fn new(first_input: &[u8]) -> Self { - let mut hash = Self { - value: [0; 32] - }; - let mut sha = Sha256::engine(); - sha.input(first_input); - hash.value = Sha256::from_engine(sha).into_inner(); - hash - } - - pub(super) fn update(&mut self, input: &[u8]) { - let mut sha = Sha256::engine(); - sha.input(self.value.as_ref()); - sha.input(input); - self.value = Sha256::from_engine(sha).into_inner(); - } -} diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index d2eb122c7c2..13eae16a380 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -9,7 +9,6 @@ use ln::peers::handshake::acts::Act; use ln::peers::handshake::states::{HandshakeState2, UninitiatedHandshakeState, AwaitingActOneHandshakeState}; mod acts; -mod hash; mod states; /// Object for managing handshakes. diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index bfc0f093b62..6ef7fe86dea 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -4,12 +4,14 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; -use ln::peers::handshake::hash::HandshakeHash; use ln::peers::handshake::acts::{Act, ActOne, ACT_ONE_LENGTH, ActTwo, ACT_TWO_LENGTH, ACT_THREE_LENGTH, ActThree}; use ln::peers::handshake::states::HandshakeState2::{AwaitingActTwo2, AwaitingActThree2, Complete2}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; +// Alias type to allow passing handshake hash easier +type HandshakeHash = [u8; 32]; + // Generate a SHA-256 hash from one or more elements macro_rules! sha256 { ( $( $x:expr ),+ ) => {{ @@ -120,12 +122,12 @@ impl IHandshakeState for UninitiatedHandshakeState { let mut hash = self.hash; // serialize act one - let (act_one, chaining_key, _) = calculate_act_message( + let (act_one, hash, chaining_key, _) = calculate_act_message( &initiator_ephemeral_private_key, &initiator_ephemeral_public_key, &responder_static_public_key, chaining_key, - &mut hash, + hash, ); Ok(( @@ -171,7 +173,7 @@ impl IHandshakeState for AwaitingActOneHandshakeState { return Err("need at least 50 bytes".to_string()); } - let mut hash = self.hash; + let hash = self.hash; let responder_static_private_key = self.responder_static_private_key; let chaining_key = self.chaining_key; let responder_ephemeral_private_key = self.responder_ephemeral_private_key; @@ -182,19 +184,19 @@ impl IHandshakeState for AwaitingActOneHandshakeState { act_one_bytes.copy_from_slice(&read_buffer[..ACT_ONE_LENGTH]); read_buffer.drain(..ACT_ONE_LENGTH); - let (initiator_ephemeral_public_key, chaining_key, _) = process_act_message( + let (initiator_ephemeral_public_key, hash, chaining_key, _) = process_act_message( act_one_bytes, &responder_static_private_key, chaining_key, - &mut hash, + hash, )?; - let (act_two, chaining_key, temporary_key) = calculate_act_message( + let (act_two, hash, chaining_key, temporary_key) = calculate_act_message( &responder_ephemeral_private_key, &responder_ephemeral_public_key, &initiator_ephemeral_public_key, chaining_key, - &mut hash, + hash, ); Ok(( @@ -225,7 +227,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; let responder_static_public_key = self.responder_static_public_key; - let mut hash = self.hash; + let hash = self.hash; let chaining_key = self.chaining_key; // 1. Read exactly 50 bytes from the network buffer @@ -233,19 +235,19 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { act_two_bytes.copy_from_slice(&read_buffer[..ACT_TWO_LENGTH]); read_buffer.drain(..ACT_TWO_LENGTH); - let (responder_ephemeral_public_key, chaining_key, temporary_key) = process_act_message( + let (responder_ephemeral_public_key, hash, chaining_key, temporary_key) = process_act_message( act_two_bytes, &initiator_ephemeral_private_key, chaining_key, - &mut hash, + hash, )?; // start serializing act three // 1. c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed()) - let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash.value, &initiator_static_public_key.serialize()); + let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash, &initiator_static_public_key.serialize()); // 2. h = SHA-256(h || c) - let hash = sha256!(concat!(hash.value, tagged_encrypted_pubkey)); + let hash = sha256!(concat!(hash, tagged_encrypted_pubkey)); // 3. se = ECDH(s.priv, re) let ecdh = ecdh(&initiator_static_private_key, &responder_ephemeral_public_key); @@ -319,7 +321,7 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { } // 4. rs = decryptWithAD(temp_k2, 1, h, c) - let remote_pubkey_vec = chacha::decrypt(&temporary_key, 1, &hash.value, &tagged_encrypted_pubkey)?; + let remote_pubkey_vec = chacha::decrypt(&temporary_key, 1, &hash, &tagged_encrypted_pubkey)?; let mut initiator_pubkey_bytes = [0u8; 33]; initiator_pubkey_bytes.copy_from_slice(remote_pubkey_vec.as_slice()); let initiator_pubkey = if let Ok(public_key) = PublicKey::from_slice(&initiator_pubkey_bytes) { @@ -329,7 +331,7 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { }; // 5. h = SHA-256(h || c) - let hash = sha256!(concat!(hash.value, tagged_encrypted_pubkey)); + let hash = sha256!(concat!(hash, tagged_encrypted_pubkey)); // 6. se = ECDH(e.priv, rs) let ecdh = ecdh(&responder_ephemeral_private_key, &initiator_pubkey); @@ -376,20 +378,16 @@ fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (H // h = SHA-256(h || responderPublicKey) let hash = sha256!(concat!(hash, responder_static_public_key.serialize())); - let hash = HandshakeHash { - value: hash - }; - (hash, chaining_key) } // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) -fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], h_hash: &mut HandshakeHash) -> ([u8; 50], SymmetricKey, SymmetricKey) { +fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: HandshakeHash) -> ([u8; 50], HandshakeHash, SymmetricKey, SymmetricKey) { // 1. e = generateKey() (passed in) // 2. h = SHA-256(h || e.pub.serializeCompressed()) let serialized_local_public_key = local_public_ephemeral_key.serialize(); - let hash = sha256!(concat!(h_hash.value, serialized_local_public_key)); + let hash = sha256!(concat!(hash, serialized_local_public_key)); // 3. ACT1: es = ECDH(e.priv, rs) // 3. ACT2: es = ECDH(e.priv, re) @@ -404,22 +402,20 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash, &[0; 0]); // 6. h = SHA-256(h || c) - *h_hash = HandshakeHash { - value: sha256!(hash, tagged_ciphertext) - }; + let hash = sha256!(hash, tagged_ciphertext); // Send m = 0 || e.pub.serializeCompressed() || c let mut act = [0u8; 50]; act[1..34].copy_from_slice(&serialized_local_public_key); act[34..].copy_from_slice(tagged_ciphertext.as_slice()); - (act, chaining_key, temporary_key) + (act, hash, chaining_key, temporary_key) } // Due to the very high similarity of acts 1 and 2, this method is used to process both // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) -fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, h_hash: &mut HandshakeHash) -> Result<(PublicKey, SymmetricKey, SymmetricKey), String> { +fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: HandshakeHash) -> Result<(PublicKey, HandshakeHash, SymmetricKey, SymmetricKey), String> { // 2.Parse the read message (m) into v, re, and c let version = act_bytes[0]; @@ -441,7 +437,7 @@ fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chain } // 4. h = SHA-256(h || re.serializeCompressed()) - let hash = sha256!(concat!(h_hash.value, ephemeral_public_key_bytes)); + let hash = sha256!(concat!(hash, ephemeral_public_key_bytes)); // 5. Act1: es = ECDH(s.priv, re) // 5. Act2: ee = ECDH(e.priv, ee) @@ -455,11 +451,9 @@ fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chain let _tag_check = chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag)?; // 8. h = SHA-256(h || c) - *h_hash = HandshakeHash { - value: sha256!(concat!(hash, chacha_tag)) - }; + let hash = sha256!(concat!(hash, chacha_tag)); - Ok((ephemeral_public_key, chaining_key, temporary_key)) + Ok((ephemeral_public_key, hash, chaining_key, temporary_key)) } fn private_key_to_public_key(private_key: &SecretKey) -> PublicKey { From 43bfce24f0441da3a2a8ca797d05823ad59dddaf Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 19:17:01 -0700 Subject: [PATCH 41/96] refactor: Combine duplicate code path for act1 and act2 Push buffer read into helper function Combines static length values of ActOne and ActTwo structs --- lightning/src/ln/peers/handshake/acts.rs | 7 ++-- lightning/src/ln/peers/handshake/states.rs | 37 ++++++++-------------- 2 files changed, 17 insertions(+), 27 deletions(-) diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs index 4f29d0e4f8d..cddc2a1ac4b 100644 --- a/lightning/src/ln/peers/handshake/acts.rs +++ b/lightning/src/ln/peers/handshake/acts.rs @@ -1,15 +1,14 @@ -pub const ACT_ONE_LENGTH: usize = 50; -pub const ACT_TWO_LENGTH: usize = 50; +pub const ACT_ONE_TWO_LENGTH: usize = 50; pub const ACT_THREE_LENGTH: usize = 66; /// Wrapper for the first act message pub struct ActOne( - pub(super) [u8; ACT_ONE_LENGTH] + pub(super) [u8; ACT_ONE_TWO_LENGTH] ); /// Wrapper for the second act message pub struct ActTwo( - pub(super) [u8; ACT_TWO_LENGTH] + pub(super) [u8; ACT_ONE_TWO_LENGTH] ); /// Wrapper for the third act message diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 6ef7fe86dea..d6c190250f7 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -4,7 +4,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; -use ln::peers::handshake::acts::{Act, ActOne, ACT_ONE_LENGTH, ActTwo, ACT_TWO_LENGTH, ACT_THREE_LENGTH, ActThree}; +use ln::peers::handshake::acts::{Act, ActOne, ACT_ONE_TWO_LENGTH, ActTwo, ACT_THREE_LENGTH, ActThree}; use ln::peers::handshake::states::HandshakeState2::{AwaitingActTwo2, AwaitingActThree2, Complete2}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; @@ -169,23 +169,14 @@ impl IHandshakeState for AwaitingActOneHandshakeState { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); - if read_buffer.len() < ACT_ONE_LENGTH { - return Err("need at least 50 bytes".to_string()); - } - let hash = self.hash; let responder_static_private_key = self.responder_static_private_key; let chaining_key = self.chaining_key; let responder_ephemeral_private_key = self.responder_ephemeral_private_key; let responder_ephemeral_public_key = self.responder_ephemeral_public_key; - // 1. Read exactly 50 bytes from the network buffer - let mut act_one_bytes = [0u8; ACT_ONE_LENGTH]; - act_one_bytes.copy_from_slice(&read_buffer[..ACT_ONE_LENGTH]); - read_buffer.drain(..ACT_ONE_LENGTH); - let (initiator_ephemeral_public_key, hash, chaining_key, _) = process_act_message( - act_one_bytes, + &mut read_buffer, &responder_static_private_key, chaining_key, hash, @@ -219,10 +210,6 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); - if read_buffer.len() < ACT_TWO_LENGTH { - return Err("need at least 50 bytes".to_string()); - } - let initiator_static_private_key = self.initiator_static_private_key; let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; @@ -230,13 +217,8 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { let hash = self.hash; let chaining_key = self.chaining_key; - // 1. Read exactly 50 bytes from the network buffer - let mut act_two_bytes = [0u8; ACT_TWO_LENGTH]; - act_two_bytes.copy_from_slice(&read_buffer[..ACT_TWO_LENGTH]); - read_buffer.drain(..ACT_TWO_LENGTH); - let (responder_ephemeral_public_key, hash, chaining_key, temporary_key) = process_act_message( - act_two_bytes, + &mut read_buffer, &initiator_ephemeral_private_key, chaining_key, hash, @@ -415,7 +397,16 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e // Due to the very high similarity of acts 1 and 2, this method is used to process both // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) -fn process_act_message(act_bytes: [u8; 50], local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: HandshakeHash) -> Result<(PublicKey, HandshakeHash, SymmetricKey, SymmetricKey), String> { +fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: HandshakeHash) -> Result<(PublicKey, HandshakeHash, SymmetricKey, SymmetricKey), String> { + // 1. Read exactly 50 bytes from the network buffer + if read_buffer.len() < ACT_ONE_TWO_LENGTH { + return Err("need at least 50 bytes".to_string()); + } + + let mut act_bytes = [0u8; ACT_ONE_TWO_LENGTH]; + act_bytes.copy_from_slice(&read_buffer[..ACT_ONE_TWO_LENGTH]); + read_buffer.drain(..ACT_ONE_TWO_LENGTH); + // 2.Parse the read message (m) into v, re, and c let version = act_bytes[0]; @@ -557,7 +548,7 @@ mod test { } // Responder::AwaitingActOne -> AwaitingActThree - // TODO: Should this fail since we don't expect data > ACT_ONE_LENGTH and likely indicates + // TODO: Should this fail since we don't expect data > ACT_ONE_TWO_LENGTH and likely indicates // a bad peer? // TODO: Should the behavior be changed to handle act1 data that is striped across multiple // next() calls? From 23c3cc585bc540f3fd103bbcb2b4f5320f491814 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 19:18:22 -0700 Subject: [PATCH 42/96] refactor: Introduce ChainingKey type alias --- lightning/src/ln/peers/handshake/states.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index d6c190250f7..b9d2047fc10 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -11,6 +11,7 @@ use ln::peers::conduit::{Conduit, SymmetricKey}; // Alias type to allow passing handshake hash easier type HandshakeHash = [u8; 32]; +type ChainingKey = [u8; 32]; // Generate a SHA-256 hash from one or more elements macro_rules! sha256 { @@ -62,7 +63,7 @@ pub struct UninitiatedHandshakeState { initiator_ephemeral_private_key: SecretKey, initiator_ephemeral_public_key: PublicKey, responder_static_public_key: PublicKey, - chaining_key: [u8; 32], + chaining_key: ChainingKey, hash: HandshakeHash, } @@ -70,7 +71,7 @@ pub struct AwaitingActOneHandshakeState { responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey, responder_ephemeral_public_key: PublicKey, - chaining_key: [u8; 32], + chaining_key: ChainingKey, hash: HandshakeHash, read_buffer: Vec } @@ -80,7 +81,7 @@ pub struct AwaitingActTwoHandshakeState { initiator_static_public_key: PublicKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey, - chaining_key: [u8; 32], + chaining_key: ChainingKey, hash: HandshakeHash, read_buffer: Vec } @@ -88,7 +89,7 @@ pub struct AwaitingActTwoHandshakeState { pub struct AwaitingActThreeHandshakeState { hash: HandshakeHash, responder_ephemeral_private_key: SecretKey, - chaining_key: [u8; 32], + chaining_key: ChainingKey, temporary_key: [u8; 32], read_buffer: Vec } @@ -346,7 +347,7 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { } // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization -fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (HandshakeHash, [u8; 32]) { +fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (HandshakeHash, ChainingKey) { let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; let prologue = b"lightning"; @@ -365,7 +366,7 @@ fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (H // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) -fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: [u8; 32], hash: HandshakeHash) -> ([u8; 50], HandshakeHash, SymmetricKey, SymmetricKey) { +fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: HandshakeHash) -> ([u8; 50], HandshakeHash, SymmetricKey, SymmetricKey) { // 1. e = generateKey() (passed in) // 2. h = SHA-256(h || e.pub.serializeCompressed()) let serialized_local_public_key = local_public_ephemeral_key.serialize(); From fcb6c965941ac6742e8a2e6337fac8a503e632d0 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 20:16:22 -0700 Subject: [PATCH 43/96] refactor: Remove Act object All consumers immediately serialize the struct so just do it for them and hide the implementation details of the handshake. --- lightning/src/ln/peers/handler.rs | 4 +- lightning/src/ln/peers/handshake/acts.rs | 41 ----------------- lightning/src/ln/peers/handshake/mod.rs | 17 +++---- lightning/src/ln/peers/handshake/states.rs | 53 ++++++++++++---------- 4 files changed, 38 insertions(+), 77 deletions(-) delete mode 100644 lightning/src/ln/peers/handshake/acts.rs diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index b8a2d076b64..c33c085d5f8 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -146,7 +146,7 @@ impl PeerState { let requires_response = next_act.is_some(); if let Some(act) = next_act { - mutable_response_buffer.push_back(act.serialize()); + mutable_response_buffer.push_back(act); } let remote_pubkey_option = handshake.get_remote_pubkey(); @@ -357,7 +357,7 @@ impl PeerManager Result, PeerHandleError> { let mut handshake = PeerHandshake::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); let (act, ..) = handshake.process_act(&[]).unwrap(); - let res = act.unwrap().serialize(); + let res = act.unwrap(); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs deleted file mode 100644 index cddc2a1ac4b..00000000000 --- a/lightning/src/ln/peers/handshake/acts.rs +++ /dev/null @@ -1,41 +0,0 @@ -pub const ACT_ONE_TWO_LENGTH: usize = 50; -pub const ACT_THREE_LENGTH: usize = 66; - -/// Wrapper for the first act message -pub struct ActOne( - pub(super) [u8; ACT_ONE_TWO_LENGTH] -); - -/// Wrapper for the second act message -pub struct ActTwo( - pub(super) [u8; ACT_ONE_TWO_LENGTH] -); - -/// Wrapper for the third act message -pub struct ActThree( - pub(super) [u8; ACT_THREE_LENGTH] -); - -/// Wrapper for any act message -pub enum Act { - One(ActOne), - Two(ActTwo), - Three(ActThree), -} - -impl Act { - /// Convert any act into a byte vector - pub fn serialize(&self) -> Vec { - match self { - &Act::One(ref act) => { - act.0.to_vec() - } - &Act::Two(ref act) => { - act.0.to_vec() - } - &Act::Three(ref act) => { - act.0.to_vec() - } - } - } -} \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 13eae16a380..07728d81fa9 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -5,10 +5,8 @@ use bitcoin::secp256k1::{PublicKey, SecretKey}; use ln::peers::conduit::Conduit; -use ln::peers::handshake::acts::Act; use ln::peers::handshake::states::{HandshakeState2, UninitiatedHandshakeState, AwaitingActOneHandshakeState}; -mod acts; mod states; /// Object for managing handshakes. @@ -49,7 +47,7 @@ impl PeerHandshake { /// Returns a tuple with the following components: /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Conduit option if the handshake was just processed to completion and messages can now be encrypted and decrypted - pub fn process_act(&mut self, input: &[u8]) -> Result<(Option, Option), String> { + pub fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option), String> { let cur_state = self.state.take().unwrap(); let (act_opt, mut next_state) = cur_state.next(input)?; @@ -78,7 +76,6 @@ mod test { use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use ln::peers::handshake::PeerHandshake; - use ln::peers::handshake::acts::Act; use ln::peers::handshake::states::HandshakeState2; struct TestCtx { @@ -123,7 +120,7 @@ mod test { macro_rules! do_process_act_or_panic { ($handshake:expr, $input:expr) => { - $handshake.process_act($input).unwrap().0.unwrap().serialize() + $handshake.process_act($input).unwrap().0.unwrap() } } @@ -154,7 +151,7 @@ mod test { fn peer_handshake_outbound_uninitiated_to_awaiting_act_two() { let mut test_ctx = TestCtx::new(); - assert_matches!(test_ctx.outbound_handshake.process_act(&[]).unwrap(), (Some(Act::One(_)), None)); + assert_matches!(test_ctx.outbound_handshake.process_act(&[]).unwrap(), (Some(_), None)); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } @@ -165,7 +162,7 @@ mod test { let mut test_ctx = TestCtx::new(); // TODO: process_act() should error if state does not use vec, but it is non-empty - assert_matches!(test_ctx.outbound_handshake.process_act(&[1]).unwrap(), (Some(Act::One(_)), None)); + assert_matches!(test_ctx.outbound_handshake.process_act(&[1]).unwrap(), (Some(_), None)); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } @@ -186,7 +183,7 @@ mod test { let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); act1.extend_from_slice(&[1]); - assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(Act::Two(_)), None)); + assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(_), None)); assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } @@ -230,7 +227,7 @@ mod test { let mut test_ctx = TestCtx::new(); let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(Act::Two(_)), None)); + assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(_), None)); assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } @@ -242,7 +239,7 @@ mod test { let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - assert_matches!(test_ctx.outbound_handshake.process_act(&act2).unwrap(), (Some(Act::Three(_)), Some(_))); + assert_matches!(test_ctx.outbound_handshake.process_act(&act2).unwrap(), (Some(_), Some(_))); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::Complete2(_))); assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index b9d2047fc10..949ec3f5817 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -4,11 +4,13 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; -use ln::peers::handshake::acts::{Act, ActOne, ACT_ONE_TWO_LENGTH, ActTwo, ACT_THREE_LENGTH, ActThree}; use ln::peers::handshake::states::HandshakeState2::{AwaitingActTwo2, AwaitingActThree2, Complete2}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; +const ACT_ONE_TWO_LENGTH: usize = 50; +const ACT_THREE_LENGTH: usize = 66; + // Alias type to allow passing handshake hash easier type HandshakeHash = [u8; 32]; type ChainingKey = [u8; 32]; @@ -42,7 +44,7 @@ pub enum HandshakeState2 { } impl HandshakeState2 { - pub(crate) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + pub(crate) fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { match self { HandshakeState2::Uninitiated2(state) => { state.next(input) }, HandshakeState2::AwaitingActOne2(state) => { state.next(input) }, @@ -54,7 +56,7 @@ impl HandshakeState2 { } trait IHandshakeState { - fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String>; + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String>; } pub struct UninitiatedHandshakeState { @@ -113,7 +115,7 @@ impl UninitiatedHandshakeState { impl IHandshakeState for UninitiatedHandshakeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) - fn next(self, _input: &[u8]) -> Result<(Option, HandshakeState2), String> { + fn next(self, _input: &[u8]) -> Result<(Option>, HandshakeState2), String> { let initiator_static_private_key = self.initiator_static_private_key; let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; @@ -132,7 +134,7 @@ impl IHandshakeState for UninitiatedHandshakeState { ); Ok(( - Some(Act::One(ActOne(act_one))), + Some(act_one.to_vec()), AwaitingActTwo2(AwaitingActTwoHandshakeState { initiator_static_private_key, initiator_static_public_key, @@ -166,7 +168,7 @@ impl AwaitingActOneHandshakeState { impl IHandshakeState for AwaitingActOneHandshakeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) - fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -192,7 +194,7 @@ impl IHandshakeState for AwaitingActOneHandshakeState { ); Ok(( - Some(Act::Two(ActTwo(act_two))), + Some(act_two), AwaitingActThree2(AwaitingActThreeHandshakeState { hash, responder_ephemeral_private_key, @@ -207,7 +209,7 @@ impl IHandshakeState for AwaitingActOneHandshakeState { impl IHandshakeState for AwaitingActTwoHandshakeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (sender) - fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -249,9 +251,11 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); // Send m = 0 || c || t over the network buffer - let mut act_three = [0u8; ACT_THREE_LENGTH]; - act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); - act_three[50..].copy_from_slice(authentication_tag.as_slice()); + let mut act_three = Vec::with_capacity(ACT_THREE_LENGTH); + act_three.extend(&[0]); + act_three.extend(&tagged_encrypted_pubkey); + act_three.extend(&authentication_tag); + assert_eq!(act_three.len(), ACT_THREE_LENGTH); // Any remaining data in the read buffer would be encrypted, so transfer ownership // to the Conduit for future use. In this case, it is unlikely that any valid data @@ -262,7 +266,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { } Ok(( - Some(Act::Three(ActThree(act_three))), + Some(act_three), Complete2(Some((conduit, responder_static_public_key))) )) } @@ -270,7 +274,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { impl IHandshakeState for AwaitingActThreeHandshakeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (receiver) - fn next(self, input: &[u8]) -> Result<(Option, HandshakeState2), String> { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -366,7 +370,7 @@ fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (H // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) -fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: HandshakeHash) -> ([u8; 50], HandshakeHash, SymmetricKey, SymmetricKey) { +fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: HandshakeHash) -> (Vec, HandshakeHash, SymmetricKey, SymmetricKey) { // 1. e = generateKey() (passed in) // 2. h = SHA-256(h || e.pub.serializeCompressed()) let serialized_local_public_key = local_public_ephemeral_key.serialize(); @@ -388,9 +392,11 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e let hash = sha256!(hash, tagged_ciphertext); // Send m = 0 || e.pub.serializeCompressed() || c - let mut act = [0u8; 50]; - act[1..34].copy_from_slice(&serialized_local_public_key); - act[34..].copy_from_slice(tagged_ciphertext.as_slice()); + let mut act = Vec::with_capacity(ACT_ONE_TWO_LENGTH); + act.extend(&[0]); + act.extend_from_slice(&serialized_local_public_key); + act.extend(&tagged_ciphertext); + assert_eq!(act.len(), ACT_ONE_TWO_LENGTH); (act, hash, chaining_key, temporary_key) } @@ -472,7 +478,6 @@ mod test { use bitcoin::secp256k1; use bitcoin::secp256k1::{PublicKey, SecretKey}; - use ln::peers::handshake::acts::Act; use ln::peers::handshake::states::{UninitiatedHandshakeState, AwaitingActOneHandshakeState, HandshakeState2}; use ln::peers::handshake::states::HandshakeState2::{AwaitingActThree2, AwaitingActTwo2, Complete2}; @@ -509,7 +514,7 @@ mod test { macro_rules! do_next_or_panic { ($state:expr, $input:expr) => { if let (Some(output_act), next_state) = $state.next($input).unwrap() { - (output_act.serialize(), next_state) + (output_act, next_state) } else { panic!(); } @@ -530,7 +535,7 @@ mod test { fn uninitiated_to_awaiting_act_two() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.initiator.next(&[]).unwrap(), (Some(Act::One(_)), AwaitingActTwo2(_))); + assert_matches!(test_ctx.initiator.next(&[]).unwrap(), (Some(_), AwaitingActTwo2(_))); } // Initiator::Uninitiated -> AwaitingActTwo (extra bytes in argument) @@ -538,7 +543,7 @@ mod test { fn uninitiated_to_awaiting_act_two_extra_bytes() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.initiator.next(&[1]).unwrap(), (Some(Act::One(_)), AwaitingActTwo2(_))); + assert_matches!(test_ctx.initiator.next(&[1]).unwrap(), (Some(_), AwaitingActTwo2(_))); } // Responder::AwaitingActOne -> Error (input too small) @@ -559,7 +564,7 @@ mod test { let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); act1.extend_from_slice(&[1]); - assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(Act::Two(_)), AwaitingActThree2(_))); + assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), AwaitingActThree2(_))); } // Responder::AwaitingActOne -> Error (bad version byte) @@ -603,7 +608,7 @@ mod test { let test_ctx = TestCtx::new(); let (act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); - assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(Act::Two(_)), AwaitingActThree2(_))); + assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), AwaitingActThree2(_))); } // Initiator::AwaitingActTwo -> Complete @@ -613,7 +618,7 @@ mod test { let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); let (act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let remote_pubkey = if let (Some(Act::Three(_)), Complete2(Some((_, remote_pubkey)))) = awaiting_act_two_state.next(&act2).unwrap() { + let remote_pubkey = if let (Some(_), Complete2(Some((_, remote_pubkey)))) = awaiting_act_two_state.next(&act2).unwrap() { remote_pubkey } else { panic!(); From 35bf1cc50335900fb75c693312996fc095e2c2f3 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 19 Aug 2020 21:21:18 -0700 Subject: [PATCH 44/96] refactor: Remove get_remote_pubkey interface Now that final process_act() returns (conduit, remote_pubkey), the callers can just receive it when the handshake is complete. --- lightning/src/ln/peers/handler.rs | 18 +++----------- lightning/src/ln/peers/handshake/mod.rs | 33 +++---------------------- 2 files changed, 8 insertions(+), 43 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index c33c085d5f8..43b239827e1 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -132,12 +132,9 @@ impl PeerState { } fn process_peer_data(&mut self, data: &[u8], mutable_response_buffer: &mut LinkedList>) -> PeerDataProcessingDecision { - let mut conduit_option = None; - let mut decision_option = None; - match self { &mut PeerState::Authenticating(ref mut handshake) => { - let (next_act, conduit) = match handshake.process_act(data) { + let (next_act, conduit_and_remote_pubkey) = match handshake.process_act(data) { Ok(act_result) => act_result, Err(e) => { return PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false }); @@ -149,23 +146,16 @@ impl PeerState { mutable_response_buffer.push_back(act); } - let remote_pubkey_option = handshake.get_remote_pubkey(); - if let Some(conduit) = conduit { - conduit_option = Some(conduit); - decision_option = Some(PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey_option)); + if let Some((conduit, remote_pubkey)) = conduit_and_remote_pubkey { + *self = PeerState::Connected(conduit); + return PeerDataProcessingDecision::CompleteHandshake(requires_response, Some(remote_pubkey)); } } &mut PeerState::Connected(ref mut conduit) => { conduit.read(data); } - }; - - if let (Some(conduit), Some(decision)) = (conduit_option, decision_option) { - *self = PeerState::Connected(conduit); - return decision; } - PeerDataProcessingDecision::Continue } } diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 07728d81fa9..472aabcd439 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -13,7 +13,6 @@ mod states; /// Currently requires explicit ephemeral private key specification. pub struct PeerHandshake { state: Option, - remote_public_key: Option, } impl PeerHandshake { @@ -21,7 +20,6 @@ impl PeerHandshake { pub fn new_outbound(private_key: &SecretKey, remote_public_key: &PublicKey, ephemeral_private_key: &SecretKey) -> Self { Self { state: Some(HandshakeState2::Uninitiated2(UninitiatedHandshakeState::new(private_key.clone(), ephemeral_private_key.clone(), remote_public_key.clone()))), - remote_public_key: Some(remote_public_key.clone()), } } @@ -29,16 +27,9 @@ impl PeerHandshake { pub fn new_inbound(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { Self { state: Some(HandshakeState2::AwaitingActOne2(AwaitingActOneHandshakeState::new(private_key.clone(), ephemeral_private_key.clone()))), - remote_public_key: None, } } - /// Return the remote public key once it has been extracted from the third act. - /// Potentially useful for inbound connections - pub fn get_remote_pubkey(&self) -> Option { - self.remote_public_key - } - /// Process act dynamically /// # Arguments /// `input`: Byte slice received from peer as part of the handshake protocol @@ -47,17 +38,14 @@ impl PeerHandshake { /// Returns a tuple with the following components: /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Conduit option if the handshake was just processed to completion and messages can now be encrypted and decrypted - pub fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option), String> { + pub fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { let cur_state = self.state.take().unwrap(); let (act_opt, mut next_state) = cur_state.next(input)?; let result = match next_state { HandshakeState2::Complete2(ref mut conduit_and_pubkey) => { - let (conduit, remote_pubkey) = conduit_and_pubkey.take().unwrap(); - self.remote_public_key = Some(remote_pubkey); - - Ok((act_opt, Some(conduit))) + Ok((act_opt, conduit_and_pubkey.take())) }, _ => { Ok((act_opt, None)) } }; @@ -80,9 +68,7 @@ mod test { struct TestCtx { outbound_handshake: PeerHandshake, - outbound_public_key: PublicKey, inbound_handshake: PeerHandshake, - inbound_public_key: PublicKey } impl TestCtx { @@ -102,9 +88,7 @@ mod test { TestCtx { outbound_handshake, - outbound_public_key, inbound_handshake, - inbound_public_key } } } @@ -130,7 +114,6 @@ mod test { let test_ctx = TestCtx::new(); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::Uninitiated2(_))); - assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } // Default Inbound::AwaitingActOne @@ -139,7 +122,6 @@ mod test { let test_ctx = TestCtx::new(); assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActOne2(_))); - assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } /* @@ -153,7 +135,6 @@ mod test { assert_matches!(test_ctx.outbound_handshake.process_act(&[]).unwrap(), (Some(_), None)); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); - assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } // Outbound::Uninitiated -> AwaitingActTwo (extra bytes in argument) @@ -164,7 +145,6 @@ mod test { // TODO: process_act() should error if state does not use vec, but it is non-empty assert_matches!(test_ctx.outbound_handshake.process_act(&[1]).unwrap(), (Some(_), None)); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); - assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } // Inbound::AwaitingActOne -> Error (input too small) @@ -185,7 +165,6 @@ mod test { assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(_), None)); assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); - assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } // Inbound::AwaitingActOne -> Error (bad version byte) @@ -229,7 +208,6 @@ mod test { assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(_), None)); assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); - assert!(test_ctx.inbound_handshake.get_remote_pubkey().is_none()); } // Outbound::AwaitingActTwo -> Complete (valid conduit) @@ -241,7 +219,6 @@ mod test { assert_matches!(test_ctx.outbound_handshake.process_act(&act2).unwrap(), (Some(_), Some(_))); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::Complete2(_))); - assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } @@ -256,14 +233,13 @@ mod test { let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); act2.extend_from_slice(&[1; 100]); - let conduit = if let (_, Some(conduit)) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { + let (conduit, _) = if let (_, Some(conduit)) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { conduit } else { panic!(); }; assert_eq!(100, conduit.decryptor.read_buffer_length()); - assert_eq!(test_ctx.outbound_handshake.get_remote_pubkey(), Some(test_ctx.inbound_public_key)); } // Outbound::AwaitingActTwo -> Error (input too small) @@ -321,7 +297,6 @@ mod test { assert_matches!(test_ctx.inbound_handshake.process_act(&act3).unwrap(), (None, Some(_))); assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::Complete2(_))); - assert_eq!(test_ctx.inbound_handshake.get_remote_pubkey(), Some(test_ctx.outbound_public_key)); } // Inbound::AwaitingActThree -> Complete (with extra bytes) @@ -335,7 +310,7 @@ mod test { let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); act3.extend_from_slice(&[2; 100]); - let conduit = if let (None, Some(conduit)) = test_ctx.inbound_handshake.process_act(&act3).unwrap() { + let (conduit, _) = if let (None, Some(conduit)) = test_ctx.inbound_handshake.process_act(&act3).unwrap() { conduit } else { panic!(); From 872bc4e56e7b82b666dea245e50ebd53d1d50f9c Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Thu, 20 Aug 2020 10:15:01 -0700 Subject: [PATCH 45/96] refactor: Clean up process_peer_data Now that the remote_pubkey is returned from process_act(), the logic can be more straightforward. Each branch is responsible for returning the next PeerState and PeerDataProcessingDecision. Remove Option from CompleteHandshake now that the PublicKey is guaranteed to exist --- lightning/src/ln/peers/handler.rs | 56 ++++++++++++++++++------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 43b239827e1..f2f3cf9bf66 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -118,7 +118,7 @@ enum PeerState { } enum PeerDataProcessingDecision { - CompleteHandshake(bool, Option), + CompleteHandshake(bool, PublicKey), Continue, Disconnect(PeerHandleError) } @@ -132,31 +132,44 @@ impl PeerState { } fn process_peer_data(&mut self, data: &[u8], mutable_response_buffer: &mut LinkedList>) -> PeerDataProcessingDecision { - match self { + let (new_state_opt, decision) = match self { &mut PeerState::Authenticating(ref mut handshake) => { - let (next_act, conduit_and_remote_pubkey) = match handshake.process_act(data) { - Ok(act_result) => act_result, + match handshake.process_act(data) { + // Any errors originating from the handshake sequence result in Disconnect Err(e) => { - return PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false }); - } - }; - - let requires_response = next_act.is_some(); - if let Some(act) = next_act { - mutable_response_buffer.push_back(act); - } + (None, PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false })) + }, + // Otherwise, handshake may or may not be complete depending on whether or not + // we receive a (conduit, pubkey) + Ok((response_vec_opt, conduit_and_remote_pubkey_opt)) => { + + // Any response generated by the handshake sequence is put into the response buffer + let requires_response = response_vec_opt.is_some(); + if let Some(response_vec) = response_vec_opt { + mutable_response_buffer.push_back(response_vec); + } - if let Some((conduit, remote_pubkey)) = conduit_and_remote_pubkey { - *self = PeerState::Connected(conduit); - return PeerDataProcessingDecision::CompleteHandshake(requires_response, Some(remote_pubkey)); + // if process_act() returns the conduit and remote_pubkey the handshake + // is complete + if let Some((conduit, remote_pubkey)) = conduit_and_remote_pubkey_opt { + (Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey)) + } else { + (None, PeerDataProcessingDecision::Continue) + } + } } - } - + }, &mut PeerState::Connected(ref mut conduit) => { conduit.read(data); + (None, PeerDataProcessingDecision::Continue) } + }; + + if let Some(new_state) = new_state_opt { + *self = new_state; } - PeerDataProcessingDecision::Continue + + decision } } @@ -556,12 +569,9 @@ impl PeerManager { + PeerDataProcessingDecision::CompleteHandshake(needs_to_send_init_message, remote_pubkey) => { send_init_message = needs_to_send_init_message; - - if let Some(key) = remote_pubkey_option { - peer.their_node_id = Some(key); - } + peer.their_node_id = Some(remote_pubkey); // insert node id match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { From c35f1b2d91487707809150d4e4578810d5aace74 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Thu, 20 Aug 2020 10:28:22 -0700 Subject: [PATCH 46/96] refactor: Doc and variable name cleanup in handshake/mod.rs Clean up loose threads (wrong docs, variable names) now that this code is in a more stable state. --- lightning/src/ln/peers/handshake/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 472aabcd439..ec5a91f6ad5 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -17,16 +17,16 @@ pub struct PeerHandshake { impl PeerHandshake { /// Instantiate a new handshake with a node identity secret key and an ephemeral private key - pub fn new_outbound(private_key: &SecretKey, remote_public_key: &PublicKey, ephemeral_private_key: &SecretKey) -> Self { + pub fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState2::Uninitiated2(UninitiatedHandshakeState::new(private_key.clone(), ephemeral_private_key.clone(), remote_public_key.clone()))), + state: Some(HandshakeState2::Uninitiated2(UninitiatedHandshakeState::new(initiator_static_private_key.clone(), initiator_ephemeral_private_key.clone(), responder_static_public_key.clone()))), } } /// Instantiate a new handshake in anticipation of a peer's first handshake act - pub fn new_inbound(private_key: &SecretKey, ephemeral_private_key: &SecretKey) -> Self { + pub fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState2::AwaitingActOne2(AwaitingActOneHandshakeState::new(private_key.clone(), ephemeral_private_key.clone()))), + state: Some(HandshakeState2::AwaitingActOne2(AwaitingActOneHandshakeState::new(responder_static_private_key.clone(), responder_ephemeral_private_key.clone()))), } } @@ -37,7 +37,7 @@ impl PeerHandshake { /// # Return values /// Returns a tuple with the following components: /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol - /// `.1`: Conduit option if the handshake was just processed to completion and messages can now be encrypted and decrypted + /// `.1`: Some(Conduit, PublicKey) if the handshake was just processed to completion and messages can now be encrypted and decrypted pub fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { let cur_state = self.state.take().unwrap(); From 378c17deeb75308d85f213bfea5b308e0135ace3 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Thu, 20 Aug 2020 13:02:14 -0700 Subject: [PATCH 47/96] tests: Finish testing handshake/mod.rs Now that the implementation is complete and swapped over, remove the duplicated tests for process_act(). At this layer, all that needs to be tested is: * The new state in PeerHandshake is set to the state returned from state_machine.next() * Any error generated from state_machine.next() is returned * Any calls to process_next() after an error was returned panic These tests are a good use case for a mocking library, but for now just leverage implementation details to trigger the proper errors and states. --- lightning/src/ln/peers/handshake/mod.rs | 305 +++--------------------- 1 file changed, 38 insertions(+), 267 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index ec5a91f6ad5..87f568e0d78 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -58,8 +58,6 @@ impl PeerHandshake { #[cfg(test)] mod test { - use hex; - use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; @@ -68,27 +66,31 @@ mod test { struct TestCtx { outbound_handshake: PeerHandshake, + outbound_static_public_key: PublicKey, inbound_handshake: PeerHandshake, + inbound_static_public_key: PublicKey } impl TestCtx { fn new() -> TestCtx { let curve = secp256k1::Secp256k1::new(); - let outbound_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); - let outbound_public_key = PublicKey::from_secret_key(&curve, &outbound_private_key); - let outbound_ephemeral_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); + let outbound_static_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let outbound_static_public_key = PublicKey::from_secret_key(&curve, &outbound_static_private_key); + let outbound_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); - let inbound_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); - let inbound_public_key = PublicKey::from_secret_key(&curve, &inbound_private_key); - let inbound_ephemeral_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); + let inbound_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let inbound_static_public_key = PublicKey::from_secret_key(&curve, &inbound_static_private_key); + let inbound_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - let outbound_handshake = PeerHandshake::new_outbound(&outbound_private_key, &inbound_public_key, &outbound_ephemeral_key); - let inbound_handshake = PeerHandshake::new_inbound(&inbound_private_key, &inbound_ephemeral_key); + let outbound_handshake = PeerHandshake::new_outbound(&outbound_static_private_key, &inbound_static_public_key, &outbound_ephemeral_private_key); + let inbound_handshake = PeerHandshake::new_inbound(&inbound_static_private_key, &inbound_ephemeral_private_key); TestCtx { outbound_handshake, + outbound_static_public_key, inbound_handshake, + inbound_static_public_key, } } } @@ -128,287 +130,56 @@ mod test { * PeerHandshake::process_act() tests */ - // Outbound::Uninitiated -> AwaitingActTwo - #[test] - fn peer_handshake_outbound_uninitiated_to_awaiting_act_two() { - let mut test_ctx = TestCtx::new(); - - assert_matches!(test_ctx.outbound_handshake.process_act(&[]).unwrap(), (Some(_), None)); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); - } - - // Outbound::Uninitiated -> AwaitingActTwo (extra bytes in argument) - #[test] - fn peer_handshake_outbound_uninitiated_to_awaiting_act_two_nonempty_input() { - let mut test_ctx = TestCtx::new(); - - // TODO: process_act() should error if state does not use vec, but it is non-empty - assert_matches!(test_ctx.outbound_handshake.process_act(&[1]).unwrap(), (Some(_), None)); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); - } - - // Inbound::AwaitingActOne -> Error (input too small) - #[test] - fn peer_handshake_new_inbound_awaiting_act_one_input_too_small() { - let mut test_ctx = TestCtx::new(); - - assert_eq!(test_ctx.inbound_handshake.process_act(&[]).err(), Some(String::from("need at least 50 bytes"))); - } - - // Inbound::AwaitingActOne -> AwaitingActThree (excess bytes) - // TODO: This should error early if we receive act3 data prior to sending act2 - #[test] - fn peer_handshake_new_inbound_awaiting_act_one_input_too_large() { - let mut test_ctx = TestCtx::new(); - let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - act1.extend_from_slice(&[1]); - - assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(_), None)); - assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); - } - - // Inbound::AwaitingActOne -> Error (bad version byte) - #[test] - fn peer_handshake_new_inbound_awaiting_act_one_bad_version() { - let mut test_ctx = TestCtx::new(); - let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - // Set bad version byte - act1[0] = 1; - - assert_eq!(test_ctx.inbound_handshake.process_act(&act1).err(), Some(String::from("unexpected version"))); - } - - // Inbound::AwaitingActOne -> Error (invalid hmac) - #[test] - fn peer_handshake_new_inbound_awaiting_act_invalid_hmac() { - let mut test_ctx = TestCtx::new(); - let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - // corrupt the ciphertext - act1[34] = 0; - - assert_eq!(test_ctx.inbound_handshake.process_act(&act1).err(), Some(String::from("invalid hmac"))); - } - - // Inbound::AwaitingActOne -> Error (invalid remote ephemeral key) - #[test] - fn peer_handshake_new_inbound_awaiting_act_invalid_remote_ephemeral_key() { - let mut test_ctx = TestCtx::new(); - let mut act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - // corrupt the ephemeral public key - act1[1] = 0; - - assert_eq!(test_ctx.inbound_handshake.process_act(&act1).err(), Some(String::from("invalid remote ephemeral public key"))); - } - - // Inbound::AwaitingActOne -> AwaitingActThree - #[test] - fn peer_handshake_new_inbound_awaiting_act_one_to_awaiting_act_three() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - - assert_matches!(test_ctx.inbound_handshake.process_act(&act1).unwrap(), (Some(_), None)); - assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActThree2(_))); - } - - // Outbound::AwaitingActTwo -> Complete (valid conduit) + // Full sequence from initiator and responder as a sanity test. State machine is tested in states.rs #[test] - fn peer_handshake_outbound_awaiting_act_two_process() { + fn full_sequence_sanity_test() { let mut test_ctx = TestCtx::new(); let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - assert_matches!(test_ctx.outbound_handshake.process_act(&act2).unwrap(), (Some(_), Some(_))); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::Complete2(_))); - } - - - // Outbound::AwaitingActTwo -> Complete (with extra data) - // Ensures that any remaining data in the read buffer is transferred to the conduit once - // the handshake is complete - // TODO: Is this valid? Don't we expect peers to need ActThree before sending additional data? - #[test] - fn peer_handshake_new_outbound_excess_bytes_after_complete_are_in_conduit() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - act2.extend_from_slice(&[1; 100]); - - let (conduit, _) = if let (_, Some(conduit)) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { - conduit + let (act3, inbound_remote_pubkey) = if let (Some(act3), Some((_, remote_pubkey))) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { + (act3, remote_pubkey) } else { panic!(); }; - assert_eq!(100, conduit.decryptor.read_buffer_length()); - } - - // Outbound::AwaitingActTwo -> Error (input too small) - #[test] - fn peer_handshake_outbound_awaiting_act_two_input_too_small() { - let mut test_ctx = TestCtx::new(); - let _act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - - assert_eq!(test_ctx.outbound_handshake.process_act(&[1]).err(), Some(String::from("need at least 50 bytes"))); - } - - // Outbound::AwaitingActTwo -> Error (bad version byte) - #[test] - fn peer_handshake_outbound_awaiting_act_two_bad_version() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - // Set version byte to 1 - act2[0] = 1; - - assert_eq!(test_ctx.outbound_handshake.process_act(&act2).err(), Some(String::from("unexpected version"))); - } - - // Outbound::AwaitingActTwo -> Error (invalid hmac) - #[test] - fn peer_handshake_outbound_awaiting_act_two_invalid_hmac() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - // corrupt the ciphertext - act2[34] = 1; - - assert_eq!(test_ctx.outbound_handshake.process_act(&act2).err(), Some(String::from("invalid hmac"))); - } - - // Outbound::AwaitingActTwo -> Error (invalid remote ephemeral key) - #[test] - fn peer_handshake_outbound_awaiting_act_two_invalid_remote_ephemeral_key() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let mut act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - // corrupt the ephemeral public key - act2[1] = 1; - - assert_eq!(test_ctx.outbound_handshake.process_act(&act2).err(), Some(String::from("invalid remote ephemeral public key"))); - } - - // Inbound::AwaitingActThree -> Complete - #[test] - fn peer_handshake_new_inbound_awaiting_act_three_to_awaiting_act_three() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - - assert_matches!(test_ctx.inbound_handshake.process_act(&act3).unwrap(), (None, Some(_))); - assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::Complete2(_))); - } - - // Inbound::AwaitingActThree -> Complete (with extra bytes) - // Ensures that any remaining data in the read buffer is transferred to the conduit once - // the handshake is complete - #[test] - fn peer_handshake_new_inbound_excess_bytes_after_complete_are_in_conduit() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - act3.extend_from_slice(&[2; 100]); - - let (conduit, _) = if let (None, Some(conduit)) = test_ctx.inbound_handshake.process_act(&act3).unwrap() { - conduit + let outbound_remote_pubkey = if let (None, Some((_, remote_pubkey))) = test_ctx.inbound_handshake.process_act(&act3).unwrap() { + remote_pubkey } else { panic!(); }; - assert_eq!(100, conduit.decryptor.read_buffer_length()); + assert_eq!(inbound_remote_pubkey, test_ctx.inbound_static_public_key); + assert_eq!(outbound_remote_pubkey, test_ctx.outbound_static_public_key); } - // Inbound::AwaitingActThree -> Error (input too small) + // Test that the internal state object matches the return from state_machine.next() + // This could make use of a mocking library to remove the dependency on the state machine. All + // that needs to be tested is that the expected state (returned) from state_machine.next() matchse + // the internal set state. #[test] - fn peer_handshake_new_inbound_awaiting_act_three_input_too_small() { + fn process_act_properly_updates_state() { let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - - assert_eq!(test_ctx.inbound_handshake.process_act(&act3[..65]).err(), Some(String::from("need at least 66 bytes"))); - } - - // Inbound::AwaitingActThree -> Error (bad version byte) - #[test] - fn peer_handshake_new_inbound_awaiting_act_three_bad_version() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - // set version byte to 1 - act3[0] = 1; - - assert_eq!(test_ctx.inbound_handshake.process_act(&act3).err(), Some(String::from("unexpected version"))); - } - - // Inbound::AwaitingActThree -> Error (invalid hmac) - #[test] - fn peer_handshake_new_inbound_awaiting_act_three_invalid_hmac() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - // trigger decryption error by corrupting byte 1 - act3[1] = 0; - - assert_eq!(test_ctx.inbound_handshake.process_act(&act3).err(), Some(String::from("invalid hmac"))); - } - - // Inbound::AwaitingActThree -> Error (invalid tag hmac) - #[test] - fn peer_handshake_new_inbound_awaiting_act_three_invalid_tag_hmac() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let mut act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - // trigger tag decryption error by corrupting byte 50 - act3[50] = 0; - - assert_eq!(test_ctx.inbound_handshake.process_act(&act3).err(), Some(String::from("invalid hmac"))); - } - - // Inbound::Complete -> Panic - #[test] - #[should_panic(expected = "no acts left to process")] - fn peer_handshake_new_inbound_complete_then_process_act() { - let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - test_ctx.inbound_handshake.process_act(&act3).unwrap(); - - do_process_act_or_panic!(test_ctx.inbound_handshake, &[]); + do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); } - // Outbound::None -> Panic + // Test that any errors from the state machine are passed back to the caller + // This could make use of a mocking library to remove the dependency on the state machine + // logic. All that needs to be tested is that an error from state_machine.next() + // results in an error in process_act() #[test] - #[should_panic(expected = "no acts left to process")] - fn peer_handshake_new_outbound_complete_then_process_act() { + fn errors_properly_returned() { let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - test_ctx.inbound_handshake.process_act(&act3).unwrap(); - - do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); + assert_matches!(test_ctx.inbound_handshake.process_act(&[]).err(), Some(_)); } - // Test the Act byte generation against known good hard-coded values in case the implementation - // changes in a symmetric way that makes the other tests useless + // Test that any use of the PeerHandshake after returning an error panics #[test] - fn peer_handshake_external_spec() { + #[should_panic(expected = "called `Option::unwrap()` on a `None` value")] + fn use_after_error_panics() { let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); - let act3 = do_process_act_or_panic!(test_ctx.outbound_handshake, &act2); - - assert_eq!(hex::encode(&act1), - "00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a"); - assert_eq!(hex::encode(&act2), - "0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae"); - assert_eq!(hex::encode(&act3), - "00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"); + assert_matches!(test_ctx.inbound_handshake.process_act(&[]).err(), Some(_)); + test_ctx.inbound_handshake.process_act(&[]).unwrap(); } } From 506315db716db7acd2d7c5d5bd8d8a105f19bd25 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Thu, 20 Aug 2020 13:46:26 -0700 Subject: [PATCH 48/96] refactor: Clean up use of Sha256 in states.rs The previous concat!() macro and the variadic sha256!() had the same functionality due to the way sha.input() works. Reduce to a common code path that now uses concat_then_sha256() in all places and reduces the number of potential copies. Where appropriate, use the actual Sha256 type. The full type usage is hard due to the usages of hkdf::derive() in other parts of the code, but this is a good start on the path to cleaner type usage. --- lightning/src/ln/peers/handshake/states.rs | 65 +++++++++------------- 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 949ec3f5817..a67ee07b37e 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -11,27 +11,16 @@ use ln::peers::conduit::{Conduit, SymmetricKey}; const ACT_ONE_TWO_LENGTH: usize = 50; const ACT_THREE_LENGTH: usize = 66; -// Alias type to allow passing handshake hash easier -type HandshakeHash = [u8; 32]; type ChainingKey = [u8; 32]; -// Generate a SHA-256 hash from one or more elements -macro_rules! sha256 { +// Generate a SHA-256 hash from one or more elements concatenated together +macro_rules! concat_then_sha256 { ( $( $x:expr ),+ ) => {{ let mut sha = Sha256::engine(); $( sha.input($x.as_ref()); )+ - Sha256::from_engine(sha).into_inner() - }} -} - -// Concatenate two slices in a Vec -macro_rules! concat { - ($arg1:expr, $arg2:expr) => {{ - let mut result = $arg1.to_vec(); - result.extend_from_slice($arg2.as_ref()); - result + Sha256::from_engine(sha) }} } @@ -65,16 +54,16 @@ pub struct UninitiatedHandshakeState { initiator_ephemeral_private_key: SecretKey, initiator_ephemeral_public_key: PublicKey, responder_static_public_key: PublicKey, - chaining_key: ChainingKey, - hash: HandshakeHash, + chaining_key: Sha256, + hash: Sha256 } pub struct AwaitingActOneHandshakeState { responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey, responder_ephemeral_public_key: PublicKey, - chaining_key: ChainingKey, - hash: HandshakeHash, + chaining_key: Sha256, + hash: Sha256, read_buffer: Vec } @@ -84,12 +73,12 @@ pub struct AwaitingActTwoHandshakeState { initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey, chaining_key: ChainingKey, - hash: HandshakeHash, + hash: Sha256, read_buffer: Vec } pub struct AwaitingActThreeHandshakeState { - hash: HandshakeHash, + hash: Sha256, responder_ephemeral_private_key: SecretKey, chaining_key: ChainingKey, temporary_key: [u8; 32], @@ -122,14 +111,14 @@ impl IHandshakeState for UninitiatedHandshakeState { let initiator_ephemeral_public_key = self.initiator_ephemeral_public_key; let responder_static_public_key = self.responder_static_public_key; let chaining_key = self.chaining_key; - let mut hash = self.hash; + let hash = self.hash; // serialize act one let (act_one, hash, chaining_key, _) = calculate_act_message( &initiator_ephemeral_private_key, &initiator_ephemeral_public_key, &responder_static_public_key, - chaining_key, + chaining_key.into_inner(), hash, ); @@ -181,7 +170,7 @@ impl IHandshakeState for AwaitingActOneHandshakeState { let (initiator_ephemeral_public_key, hash, chaining_key, _) = process_act_message( &mut read_buffer, &responder_static_private_key, - chaining_key, + chaining_key.into_inner(), hash, )?; @@ -232,7 +221,7 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash, &initiator_static_public_key.serialize()); // 2. h = SHA-256(h || c) - let hash = sha256!(concat!(hash, tagged_encrypted_pubkey)); + let hash = concat_then_sha256!(hash, tagged_encrypted_pubkey); // 3. se = ECDH(s.priv, re) let ecdh = ecdh(&initiator_static_private_key, &responder_ephemeral_public_key); @@ -282,7 +271,7 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { return Err("need at least 66 bytes".to_string()); } - let mut hash = self.hash; + let hash = self.hash; let temporary_key = self.temporary_key; let responder_ephemeral_private_key = self.responder_ephemeral_private_key; let chaining_key = self.chaining_key; @@ -318,7 +307,7 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { }; // 5. h = SHA-256(h || c) - let hash = sha256!(concat!(hash, tagged_encrypted_pubkey)); + let hash = concat_then_sha256!(hash, tagged_encrypted_pubkey); // 6. se = ECDH(e.priv, rs) let ecdh = ecdh(&responder_ephemeral_private_key, &initiator_pubkey); @@ -351,30 +340,30 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { } // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state-initialization -fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (HandshakeHash, ChainingKey) { +fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (Sha256, Sha256) { let protocol_name = b"Noise_XK_secp256k1_ChaChaPoly_SHA256"; let prologue = b"lightning"; // 1. h = SHA-256(protocolName) // 2. ck = h - let chaining_key = sha256!(protocol_name); + let chaining_key = concat_then_sha256!(protocol_name); // 3. h = SHA-256(h || prologue) - let hash = sha256!(concat!(chaining_key, prologue)); + let hash = concat_then_sha256!(chaining_key, prologue); // h = SHA-256(h || responderPublicKey) - let hash = sha256!(concat!(hash, responder_static_public_key.serialize())); + let hash = concat_then_sha256!(hash, responder_static_public_key.serialize()); (hash, chaining_key) } // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) -fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: HandshakeHash) -> (Vec, HandshakeHash, SymmetricKey, SymmetricKey) { +fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: Sha256) -> (Vec, Sha256, SymmetricKey, SymmetricKey) { // 1. e = generateKey() (passed in) // 2. h = SHA-256(h || e.pub.serializeCompressed()) let serialized_local_public_key = local_public_ephemeral_key.serialize(); - let hash = sha256!(concat!(hash, serialized_local_public_key)); + let hash = concat_then_sha256!(hash, serialized_local_public_key); // 3. ACT1: es = ECDH(e.priv, rs) // 3. ACT2: es = ECDH(e.priv, re) @@ -389,7 +378,7 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash, &[0; 0]); // 6. h = SHA-256(h || c) - let hash = sha256!(hash, tagged_ciphertext); + let hash = concat_then_sha256!(hash, tagged_ciphertext); // Send m = 0 || e.pub.serializeCompressed() || c let mut act = Vec::with_capacity(ACT_ONE_TWO_LENGTH); @@ -404,7 +393,7 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e // Due to the very high similarity of acts 1 and 2, this method is used to process both // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) -fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, chaining_key: SymmetricKey, hash: HandshakeHash) -> Result<(PublicKey, HandshakeHash, SymmetricKey, SymmetricKey), String> { +fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, chaining_key: ChainingKey, hash: Sha256) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), String> { // 1. Read exactly 50 bytes from the network buffer if read_buffer.len() < ACT_ONE_TWO_LENGTH { return Err("need at least 50 bytes".to_string()); @@ -435,7 +424,7 @@ fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, } // 4. h = SHA-256(h || re.serializeCompressed()) - let hash = sha256!(concat!(hash, ephemeral_public_key_bytes)); + let hash = concat_then_sha256!(hash, ephemeral_public_key_bytes); // 5. Act1: es = ECDH(s.priv, re) // 5. Act2: ee = ECDH(e.priv, ee) @@ -449,7 +438,7 @@ fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, let _tag_check = chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag)?; // 8. h = SHA-256(h || c) - let hash = sha256!(concat!(hash, chacha_tag)); + let hash = concat_then_sha256!(hash, chacha_tag); Ok((ephemeral_public_key, hash, chaining_key, temporary_key)) } @@ -466,9 +455,7 @@ fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> SymmetricKey { pk_object.mul_assign(&curve, &private_key[..]).expect("invalid multiplication"); let preimage = pk_object.serialize(); - let mut sha = Sha256::engine(); - sha.input(preimage.as_ref()); - Sha256::from_engine(sha).into_inner() + concat_then_sha256!(preimage).into_inner() } #[cfg(test)] From 155f90e083bbb3f63683ca79ac2775ac4d2d0c42 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sat, 22 Aug 2020 14:14:47 -0700 Subject: [PATCH 49/96] refactor: Clean up hkdf::derive and add test Add documentation and a unit test against the relevant test vector from the RFC. --- lightning/src/ln/peers/hkdf.rs | 81 ++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/lightning/src/ln/peers/hkdf.rs b/lightning/src/ln/peers/hkdf.rs index 48415594114..6ac1391666d 100644 --- a/lightning/src/ln/peers/hkdf.rs +++ b/lightning/src/ln/peers/hkdf.rs @@ -1,18 +1,71 @@ use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine}; use bitcoin::hashes::sha256::Hash as Sha256; -pub fn derive(salt: &[u8], master: &[u8]) -> ([u8; 32], [u8; 32]) { - let mut hmac = HmacEngine::::new(salt); - hmac.input(master); - let prk = Hmac::from_engine(hmac).into_inner(); // prk = sha256(master) - - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&[1; 1]); - let t1 = Hmac::from_engine(hmac).into_inner(); // t1 = sha256(prk | 1) - - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&t1); - hmac.input(&[2; 1]); - // sha256(prk | t1 | 2) = sha256(sha256(master) | sha256(sha256(sha256(master) | 1) | 2) - (t1, Hmac::from_engine(hmac).into_inner()) +// Allows 1 or more inputs and "concatenates" them together using the input() function +// of HmacEngine:: +macro_rules! hmac_hash { + ( $salt:expr, ($( $input:expr ),+ )) => {{ + let mut engine = HmacEngine::::new($salt); + $( + engine.input($input); + )+ + Hmac::from_engine(engine).into_inner() + }} } + +/// Implements HKDF defined in [BOLT #8](https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#handshake-state) +/// [RFC 5869](https://tools.ietf.org/html/rfc5869pub) +/// Returns the first 64 octets as two 32 byte arrays +pub(super) fn derive(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) { + // 2.1. Notation + // + // HMAC-Hash denotes the HMAC function [HMAC] instantiated with hash + // function 'Hash'. HMAC always has two arguments: the first is a key + // and the second an input (or message). (Note that in the extract + // step, 'IKM' is used as the HMAC input, not as the HMAC key.) + // + // When the message is composed of several elements we use concatenation + // (denoted |) in the second argument; for example, HMAC(K, elem1 | + // elem2 | elem3). + + // 2.2. Step 1: Extract + // HKDF-Extract(salt, IKM) -> PRK + // PRK = HMAC-Hash(salt, IKM) + let prk = hmac_hash!(salt, (ikm)); + + // 2.3. Step 2: Expand + // HKDF-Expand(PRK, info, L) -> OKM + // N = ceil(L/HashLen) + // T = T(1) | T(2) | T(3) | ... | T(N) + // OKM = first L octets of T + // + // where: + // T(0) = empty string (zero length) + // T(1) = HMAC-Hash(PRK, T(0) | info | 0x01) + let t1 = hmac_hash!(&prk, (&[1])); + // T(2) = HMAC-Hash(PRK, T(1) | info | 0x02) + let t2 = hmac_hash!(&prk, (&t1, &[2])); + + return (t1, t2) +} + +// Appendix A. Test Vectors +#[cfg(test)] +mod test { + use hex; + use ln::peers::hkdf::derive; + + // Test with SHA-256 and zero-length salt/info + // Our implementation uses a zero-length info field and returns the first 64 octets. As a result, + // this test will be a prefix match on the vector provided by the RFC which is 42 bytes. + #[test] + fn rfc_5869_test_vector_3() { + let ikm = hex::decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b").unwrap(); + let (t1, t2) = derive(&[], &ikm); + + let mut calculated_okm = t1.to_vec(); + calculated_okm.extend_from_slice(&t2); + calculated_okm.truncate(42); + assert_eq!(calculated_okm, hex::decode("8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8").unwrap()); + } +} \ No newline at end of file From fc4d7ef58c3c500f459d5af8834e03b5c191cd4a Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Thu, 20 Aug 2020 14:09:57 -0700 Subject: [PATCH 50/96] refactor: Rename Handshake2 and related structs/enums --- lightning/src/ln/peers/handshake/mod.rs | 18 +-- lightning/src/ln/peers/handshake/states.rs | 123 +++++++++++---------- 2 files changed, 74 insertions(+), 67 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 87f568e0d78..6970e2a6c9e 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -5,28 +5,28 @@ use bitcoin::secp256k1::{PublicKey, SecretKey}; use ln::peers::conduit::Conduit; -use ln::peers::handshake::states::{HandshakeState2, UninitiatedHandshakeState, AwaitingActOneHandshakeState}; +use ln::peers::handshake::states::{HandshakeState, InitiatorStartingState, ResponderAwaitingActOneState}; mod states; /// Object for managing handshakes. /// Currently requires explicit ephemeral private key specification. pub struct PeerHandshake { - state: Option, + state: Option, } impl PeerHandshake { /// Instantiate a new handshake with a node identity secret key and an ephemeral private key pub fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState2::Uninitiated2(UninitiatedHandshakeState::new(initiator_static_private_key.clone(), initiator_ephemeral_private_key.clone(), responder_static_public_key.clone()))), + state: Some(HandshakeState::InitiatorStarting(InitiatorStartingState::new(initiator_static_private_key.clone(), initiator_ephemeral_private_key.clone(), responder_static_public_key.clone()))), } } /// Instantiate a new handshake in anticipation of a peer's first handshake act pub fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState2::AwaitingActOne2(AwaitingActOneHandshakeState::new(responder_static_private_key.clone(), responder_ephemeral_private_key.clone()))), + state: Some(HandshakeState::ResponderAwaitingActOne(ResponderAwaitingActOneState::new(responder_static_private_key.clone(), responder_ephemeral_private_key.clone()))), } } @@ -44,7 +44,7 @@ impl PeerHandshake { let (act_opt, mut next_state) = cur_state.next(input)?; let result = match next_state { - HandshakeState2::Complete2(ref mut conduit_and_pubkey) => { + HandshakeState::Complete(ref mut conduit_and_pubkey) => { Ok((act_opt, conduit_and_pubkey.take())) }, _ => { Ok((act_opt, None)) } @@ -62,7 +62,7 @@ mod test { use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use ln::peers::handshake::PeerHandshake; - use ln::peers::handshake::states::HandshakeState2; + use ln::peers::handshake::states::HandshakeState; struct TestCtx { outbound_handshake: PeerHandshake, @@ -115,7 +115,7 @@ mod test { fn peer_handshake_new_outbound() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::Uninitiated2(_))); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::InitiatorStarting(_))); } // Default Inbound::AwaitingActOne @@ -123,7 +123,7 @@ mod test { fn peer_handshake_new_inbound() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState2::AwaitingActOne2(_))); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::ResponderAwaitingActOne(_))); } /* @@ -161,7 +161,7 @@ mod test { fn process_act_properly_updates_state() { let mut test_ctx = TestCtx::new(); do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState2::AwaitingActTwo2(_))); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::InitiatorAwaitingActTwo(_))); } // Test that any errors from the state machine are passed back to the caller diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index a67ee07b37e..1434cf28d82 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -4,7 +4,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; -use ln::peers::handshake::states::HandshakeState2::{AwaitingActTwo2, AwaitingActThree2, Complete2}; +use ln::peers::handshake::states::HandshakeState::{InitiatorAwaitingActTwo, ResponderAwaitingActThree, Complete}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; @@ -24,31 +24,35 @@ macro_rules! concat_then_sha256 { }} } -pub enum HandshakeState2 { - Uninitiated2(UninitiatedHandshakeState), - AwaitingActOne2(AwaitingActOneHandshakeState), - AwaitingActTwo2(AwaitingActTwoHandshakeState), - AwaitingActThree2(AwaitingActThreeHandshakeState), - Complete2(Option<(Conduit, PublicKey)>), +pub enum HandshakeState { + InitiatorStarting(InitiatorStartingState), + ResponderAwaitingActOne(ResponderAwaitingActOneState), + InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState), + ResponderAwaitingActThree(ResponderAwaitingActThreeState), + Complete(Option<(Conduit, PublicKey)>), } -impl HandshakeState2 { - pub(crate) fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { +// Trait for all individual states to implement that ensure HandshakeState::next() can +// delegate to a common function signature. +trait IHandshakeState { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String>; +} + +// Enum dispatch for state machine. Single public interface can statically dispatch to all states +impl HandshakeState { + pub fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { match self { - HandshakeState2::Uninitiated2(state) => { state.next(input) }, - HandshakeState2::AwaitingActOne2(state) => { state.next(input) }, - HandshakeState2::AwaitingActTwo2(state) => { state.next(input) }, - HandshakeState2::AwaitingActThree2(state) => { state.next(input) }, - HandshakeState2::Complete2(_conduit) => { panic!("no acts left to process") } + HandshakeState::InitiatorStarting(state) => { state.next(input) }, + HandshakeState::ResponderAwaitingActOne(state) => { state.next(input) }, + HandshakeState::InitiatorAwaitingActTwo(state) => { state.next(input) }, + HandshakeState::ResponderAwaitingActThree(state) => { state.next(input) }, + HandshakeState::Complete(_conduit) => { panic!("no acts left to process") } } } } -trait IHandshakeState { - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String>; -} - -pub struct UninitiatedHandshakeState { +// Handshake state of the Initiator prior to generating Act 1 +pub struct InitiatorStartingState { initiator_static_private_key: SecretKey, initiator_static_public_key: PublicKey, initiator_ephemeral_private_key: SecretKey, @@ -58,7 +62,8 @@ pub struct UninitiatedHandshakeState { hash: Sha256 } -pub struct AwaitingActOneHandshakeState { +// Handshake state of the Responder prior to receiving Act 1 +pub struct ResponderAwaitingActOneState { responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey, responder_ephemeral_public_key: PublicKey, @@ -67,7 +72,8 @@ pub struct AwaitingActOneHandshakeState { read_buffer: Vec } -pub struct AwaitingActTwoHandshakeState { +// Handshake state of the Initiator prior to receiving Act 2 +pub struct InitiatorAwaitingActTwoState { initiator_static_private_key: SecretKey, initiator_static_public_key: PublicKey, initiator_ephemeral_private_key: SecretKey, @@ -77,7 +83,8 @@ pub struct AwaitingActTwoHandshakeState { read_buffer: Vec } -pub struct AwaitingActThreeHandshakeState { +// Handshake state of the Responder prior to receiving Act 3 +pub struct ResponderAwaitingActThreeState { hash: Sha256, responder_ephemeral_private_key: SecretKey, chaining_key: ChainingKey, @@ -85,12 +92,12 @@ pub struct AwaitingActThreeHandshakeState { read_buffer: Vec } -impl UninitiatedHandshakeState { +impl InitiatorStartingState { pub(crate) fn new(initiator_static_private_key: SecretKey, initiator_ephemeral_private_key: SecretKey, responder_static_public_key: PublicKey) -> Self { let initiator_static_public_key = private_key_to_public_key(&initiator_static_private_key); let (hash, chaining_key) = handshake_state_initialization(&responder_static_public_key); let initiator_ephemeral_public_key = private_key_to_public_key(&initiator_ephemeral_private_key); - UninitiatedHandshakeState { + InitiatorStartingState { initiator_static_private_key, initiator_static_public_key, initiator_ephemeral_private_key, @@ -102,9 +109,9 @@ impl UninitiatedHandshakeState { } } -impl IHandshakeState for UninitiatedHandshakeState { +impl IHandshakeState for InitiatorStartingState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) - fn next(self, _input: &[u8]) -> Result<(Option>, HandshakeState2), String> { + fn next(self, _input: &[u8]) -> Result<(Option>, HandshakeState), String> { let initiator_static_private_key = self.initiator_static_private_key; let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; @@ -124,7 +131,7 @@ impl IHandshakeState for UninitiatedHandshakeState { Ok(( Some(act_one.to_vec()), - AwaitingActTwo2(AwaitingActTwoHandshakeState { + InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState { initiator_static_private_key, initiator_static_public_key, initiator_ephemeral_private_key, @@ -137,13 +144,13 @@ impl IHandshakeState for UninitiatedHandshakeState { } } -impl AwaitingActOneHandshakeState { +impl ResponderAwaitingActOneState { pub(crate) fn new(responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey) -> Self { let responder_static_public_key = private_key_to_public_key(&responder_static_private_key); let (hash, chaining_key) = handshake_state_initialization(&responder_static_public_key); let responder_ephemeral_public_key = private_key_to_public_key(&responder_ephemeral_private_key); - AwaitingActOneHandshakeState { + ResponderAwaitingActOneState { responder_static_private_key, responder_ephemeral_private_key, responder_ephemeral_public_key, @@ -154,10 +161,10 @@ impl AwaitingActOneHandshakeState { } } -impl IHandshakeState for AwaitingActOneHandshakeState { +impl IHandshakeState for ResponderAwaitingActOneState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -184,7 +191,7 @@ impl IHandshakeState for AwaitingActOneHandshakeState { Ok(( Some(act_two), - AwaitingActThree2(AwaitingActThreeHandshakeState { + ResponderAwaitingActThree(ResponderAwaitingActThreeState { hash, responder_ephemeral_private_key, chaining_key, @@ -195,10 +202,10 @@ impl IHandshakeState for AwaitingActOneHandshakeState { } } -impl IHandshakeState for AwaitingActTwoHandshakeState { +impl IHandshakeState for InitiatorAwaitingActTwoState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (sender) - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -256,14 +263,14 @@ impl IHandshakeState for AwaitingActTwoHandshakeState { Ok(( Some(act_three), - Complete2(Some((conduit, responder_static_public_key))) + Complete(Some((conduit, responder_static_public_key))) )) } } -impl IHandshakeState for AwaitingActThreeHandshakeState { +impl IHandshakeState for ResponderAwaitingActThreeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (receiver) - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState2), String> { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); @@ -334,7 +341,7 @@ impl IHandshakeState for AwaitingActThreeHandshakeState { Ok(( None, - Complete2(Some((conduit, initiator_pubkey))) + Complete(Some((conduit, initiator_pubkey))) )) } } @@ -465,13 +472,13 @@ mod test { use bitcoin::secp256k1; use bitcoin::secp256k1::{PublicKey, SecretKey}; - use ln::peers::handshake::states::{UninitiatedHandshakeState, AwaitingActOneHandshakeState, HandshakeState2}; - use ln::peers::handshake::states::HandshakeState2::{AwaitingActThree2, AwaitingActTwo2, Complete2}; + use ln::peers::handshake::states::{InitiatorStartingState, ResponderAwaitingActOneState, HandshakeState}; + use ln::peers::handshake::states::HandshakeState::{ResponderAwaitingActThree, InitiatorAwaitingActTwo, Complete}; struct TestCtx { - initiator: HandshakeState2, + initiator: HandshakeState, initiator_public_key: PublicKey, - responder: HandshakeState2, + responder: HandshakeState, responder_static_public_key: PublicKey } @@ -486,13 +493,13 @@ mod test { let responder_static_public_key = PublicKey::from_secret_key(&curve, &responder_static_private_key); let responder_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - let initiator = UninitiatedHandshakeState::new(initiator_static_private_key, initiator_ephemeral_private_key, responder_static_public_key); - let responder = AwaitingActOneHandshakeState::new(responder_static_private_key, responder_ephemeral_private_key); + let initiator = InitiatorStartingState::new(initiator_static_private_key, initiator_ephemeral_private_key, responder_static_public_key); + let responder = ResponderAwaitingActOneState::new(responder_static_private_key, responder_ephemeral_private_key); TestCtx { - initiator: HandshakeState2::Uninitiated2(initiator), + initiator: HandshakeState::InitiatorStarting(initiator), initiator_public_key, - responder: HandshakeState2::AwaitingActOne2(responder), + responder: HandshakeState::ResponderAwaitingActOne(responder), responder_static_public_key, } } @@ -517,20 +524,20 @@ mod test { } } - // Initiator::Uninitiated -> AwaitingActTwo + // Initiator::Starting -> AwaitingActTwo #[test] - fn uninitiated_to_awaiting_act_two() { + fn starting_to_awaiting_act_two() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.initiator.next(&[]).unwrap(), (Some(_), AwaitingActTwo2(_))); + assert_matches!(test_ctx.initiator.next(&[]).unwrap(), (Some(_), InitiatorAwaitingActTwo(_))); } - // Initiator::Uninitiated -> AwaitingActTwo (extra bytes in argument) + // Initiator::Starting -> AwaitingActTwo (extra bytes in argument) #[test] - fn uninitiated_to_awaiting_act_two_extra_bytes() { + fn starting_to_awaiting_act_two_extra_bytes() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.initiator.next(&[1]).unwrap(), (Some(_), AwaitingActTwo2(_))); + assert_matches!(test_ctx.initiator.next(&[1]).unwrap(), (Some(_), InitiatorAwaitingActTwo(_))); } // Responder::AwaitingActOne -> Error (input too small) @@ -551,7 +558,7 @@ mod test { let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); act1.extend_from_slice(&[1]); - assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), AwaitingActThree2(_))); + assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), ResponderAwaitingActThree(_))); } // Responder::AwaitingActOne -> Error (bad version byte) @@ -595,7 +602,7 @@ mod test { let test_ctx = TestCtx::new(); let (act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); - assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), AwaitingActThree2(_))); + assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), ResponderAwaitingActThree(_))); } // Initiator::AwaitingActTwo -> Complete @@ -605,7 +612,7 @@ mod test { let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); let (act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let remote_pubkey = if let (Some(_), Complete2(Some((_, remote_pubkey)))) = awaiting_act_two_state.next(&act2).unwrap() { + let remote_pubkey = if let (Some(_), Complete(Some((_, remote_pubkey)))) = awaiting_act_two_state.next(&act2).unwrap() { remote_pubkey } else { panic!(); @@ -627,7 +634,7 @@ mod test { let (_act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); - let conduit = if let Complete2(Some((conduit, _))) = complete_state { + let conduit = if let Complete(Some((conduit, _))) = complete_state { conduit } else { panic!(); @@ -689,7 +696,7 @@ mod test { let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); let (act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); - let remote_pubkey = if let (None, Complete2(Some((_, remote_pubkey)))) = awaiting_act_three_state.next(&act3).unwrap() { + let remote_pubkey = if let (None, Complete(Some((_, remote_pubkey)))) = awaiting_act_three_state.next(&act3).unwrap() { remote_pubkey } else { panic!(); @@ -709,7 +716,7 @@ mod test { let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); act3.extend_from_slice(&[2; 100]); - let conduit = if let (_, Complete2(Some((conduit, _)))) = awaiting_act_three_state.next(&act3).unwrap() { + let conduit = if let (_, Complete(Some((conduit, _)))) = awaiting_act_three_state.next(&act3).unwrap() { conduit } else { panic!(); From 8096367280843a8a084521451fb8d757441f1836 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Thu, 20 Aug 2020 16:11:10 -0700 Subject: [PATCH 51/96] refactor: Clean up visibility/imports in handshake/ Not using IHandshakeState slipped through the cracks until this point, but using it makes the enum dispatch follow a more standardized pattern. --- lightning/src/ln/peers/handshake/mod.rs | 11 +++---- lightning/src/ln/peers/handshake/states.rs | 38 +++++++++++++--------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 6970e2a6c9e..52efde4ad97 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -5,7 +5,7 @@ use bitcoin::secp256k1::{PublicKey, SecretKey}; use ln::peers::conduit::Conduit; -use ln::peers::handshake::states::{HandshakeState, InitiatorStartingState, ResponderAwaitingActOneState}; +use ln::peers::handshake::states::{HandshakeState, IHandshakeState}; mod states; @@ -19,14 +19,14 @@ impl PeerHandshake { /// Instantiate a new handshake with a node identity secret key and an ephemeral private key pub fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState::InitiatorStarting(InitiatorStartingState::new(initiator_static_private_key.clone(), initiator_ephemeral_private_key.clone(), responder_static_public_key.clone()))), + state: Some(HandshakeState::new_initiator(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key)) } } /// Instantiate a new handshake in anticipation of a peer's first handshake act pub fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState::ResponderAwaitingActOne(ResponderAwaitingActOneState::new(responder_static_private_key.clone(), responder_ephemeral_private_key.clone()))), + state: Some(HandshakeState::new_responder(responder_static_private_key, responder_ephemeral_private_key)) } } @@ -58,12 +58,11 @@ impl PeerHandshake { #[cfg(test)] mod test { + use super::*; + use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; - use ln::peers::handshake::PeerHandshake; - use ln::peers::handshake::states::HandshakeState; - struct TestCtx { outbound_handshake: PeerHandshake, outbound_static_public_key: PublicKey, diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 1434cf28d82..a95ee0158fc 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -4,7 +4,6 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; -use ln::peers::handshake::states::HandshakeState::{InitiatorAwaitingActTwo, ResponderAwaitingActThree, Complete}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; @@ -24,7 +23,7 @@ macro_rules! concat_then_sha256 { }} } -pub enum HandshakeState { +pub(super) enum HandshakeState { InitiatorStarting(InitiatorStartingState), ResponderAwaitingActOne(ResponderAwaitingActOneState), InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState), @@ -34,13 +33,22 @@ pub enum HandshakeState { // Trait for all individual states to implement that ensure HandshakeState::next() can // delegate to a common function signature. -trait IHandshakeState { +pub(super) trait IHandshakeState { fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String>; } // Enum dispatch for state machine. Single public interface can statically dispatch to all states impl HandshakeState { - pub fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { + pub(super) fn new_initiator(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { + HandshakeState::InitiatorStarting(InitiatorStartingState::new(initiator_static_private_key.clone(), initiator_ephemeral_private_key.clone(), responder_static_public_key.clone())) + } + pub(super) fn new_responder(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { + HandshakeState::ResponderAwaitingActOne(ResponderAwaitingActOneState::new(responder_static_private_key.clone(), responder_ephemeral_private_key.clone())) + } +} + +impl IHandshakeState for HandshakeState { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { match self { HandshakeState::InitiatorStarting(state) => { state.next(input) }, HandshakeState::ResponderAwaitingActOne(state) => { state.next(input) }, @@ -52,7 +60,7 @@ impl HandshakeState { } // Handshake state of the Initiator prior to generating Act 1 -pub struct InitiatorStartingState { +pub(super) struct InitiatorStartingState { initiator_static_private_key: SecretKey, initiator_static_public_key: PublicKey, initiator_ephemeral_private_key: SecretKey, @@ -63,7 +71,7 @@ pub struct InitiatorStartingState { } // Handshake state of the Responder prior to receiving Act 1 -pub struct ResponderAwaitingActOneState { +pub(super) struct ResponderAwaitingActOneState { responder_static_private_key: SecretKey, responder_ephemeral_private_key: SecretKey, responder_ephemeral_public_key: PublicKey, @@ -73,7 +81,7 @@ pub struct ResponderAwaitingActOneState { } // Handshake state of the Initiator prior to receiving Act 2 -pub struct InitiatorAwaitingActTwoState { +pub(super) struct InitiatorAwaitingActTwoState { initiator_static_private_key: SecretKey, initiator_static_public_key: PublicKey, initiator_ephemeral_private_key: SecretKey, @@ -84,7 +92,7 @@ pub struct InitiatorAwaitingActTwoState { } // Handshake state of the Responder prior to receiving Act 3 -pub struct ResponderAwaitingActThreeState { +pub(super) struct ResponderAwaitingActThreeState { hash: Sha256, responder_ephemeral_private_key: SecretKey, chaining_key: ChainingKey, @@ -131,7 +139,7 @@ impl IHandshakeState for InitiatorStartingState { Ok(( Some(act_one.to_vec()), - InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState { + HandshakeState::InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState { initiator_static_private_key, initiator_static_public_key, initiator_ephemeral_private_key, @@ -191,7 +199,7 @@ impl IHandshakeState for ResponderAwaitingActOneState { Ok(( Some(act_two), - ResponderAwaitingActThree(ResponderAwaitingActThreeState { + HandshakeState::ResponderAwaitingActThree(ResponderAwaitingActThreeState { hash, responder_ephemeral_private_key, chaining_key, @@ -263,7 +271,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { Ok(( Some(act_three), - Complete(Some((conduit, responder_static_public_key))) + HandshakeState::Complete(Some((conduit, responder_static_public_key))) )) } } @@ -341,7 +349,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { Ok(( None, - Complete(Some((conduit, initiator_pubkey))) + HandshakeState::Complete(Some((conduit, initiator_pubkey))) )) } } @@ -467,14 +475,14 @@ fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> SymmetricKey { #[cfg(test)] mod test { + use super::*; + use super::HandshakeState::*; + use hex; use bitcoin::secp256k1; use bitcoin::secp256k1::{PublicKey, SecretKey}; - use ln::peers::handshake::states::{InitiatorStartingState, ResponderAwaitingActOneState, HandshakeState}; - use ln::peers::handshake::states::HandshakeState::{ResponderAwaitingActThree, InitiatorAwaitingActTwo, Complete}; - struct TestCtx { initiator: HandshakeState, initiator_public_key: PublicKey, From 3755dfb731f0978f79ada9789d13e7f1642b0036 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Fri, 21 Aug 2020 10:41:55 -0700 Subject: [PATCH 52/96] tests: Leverage RFC test vectors in unit tests This uses hard-coded test vectors to minimize the code under test as well as ensures full coverage. One additional test was added to account for an Act3 bad rs value. --- lightning/src/ln/peers/handshake/states.rs | 216 ++++++++++++--------- 1 file changed, 122 insertions(+), 94 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index a95ee0158fc..d7de6845b71 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -119,7 +119,12 @@ impl InitiatorStartingState { impl IHandshakeState for InitiatorStartingState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) - fn next(self, _input: &[u8]) -> Result<(Option>, HandshakeState), String> { + fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { + + if input.len() > 0 { + return Err("first call for initiator must be empty".to_string()); + } + let initiator_static_private_key = self.initiator_static_private_key; let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; @@ -474,6 +479,8 @@ fn ecdh(private_key: &SecretKey, public_key: &PublicKey) -> SymmetricKey { } #[cfg(test)] +// Reference RFC test vectors for hard-coded values +// https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#appendix-a-transport-test-vectors mod test { use super::*; use super::HandshakeState::*; @@ -487,7 +494,11 @@ mod test { initiator: HandshakeState, initiator_public_key: PublicKey, responder: HandshakeState, - responder_static_public_key: PublicKey + responder_static_public_key: PublicKey, + valid_act1: Vec, + valid_act2: Vec, + valid_act3: Vec, + } impl TestCtx { @@ -509,6 +520,9 @@ mod test { initiator_public_key, responder: HandshakeState::ResponderAwaitingActOne(responder), responder_static_public_key, + valid_act1: hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap(), + valid_act2: hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap(), + valid_act3: hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap() } } } @@ -536,23 +550,31 @@ mod test { #[test] fn starting_to_awaiting_act_two() { let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - assert_matches!(test_ctx.initiator.next(&[]).unwrap(), (Some(_), InitiatorAwaitingActTwo(_))); + assert_eq!(act1, test_ctx.valid_act1); + assert_matches!(awaiting_act_two_state, InitiatorAwaitingActTwo(_)); } // Initiator::Starting -> AwaitingActTwo (extra bytes in argument) #[test] fn starting_to_awaiting_act_two_extra_bytes() { let test_ctx = TestCtx::new(); + let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - assert_matches!(test_ctx.initiator.next(&[1]).unwrap(), (Some(_), InitiatorAwaitingActTwo(_))); + assert_eq!(act1, test_ctx.valid_act1); + assert_matches!(awaiting_act_two_state, InitiatorAwaitingActTwo(_)); } - // Responder::AwaitingActOne -> Error (input too small) + // Responder::AwaitingActOne -> AwaitingActThree + // RFC test vector: transport-responder successful handshake #[test] - fn awaiting_act_one_to_awaiting_act_three_input_too_small() { + fn awaiting_act_one_to_awaiting_act_three() { let test_ctx = TestCtx::new(); - assert_eq!(test_ctx.responder.next(&[]).err(), Some(String::from("need at least 50 bytes"))) + let (act2, awaiting_act_three_state) = test_ctx.responder.next(&test_ctx.valid_act1).unwrap(); + + assert_eq!(act2.unwrap(), test_ctx.valid_act2); + assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_)); } // Responder::AwaitingActOne -> AwaitingActThree @@ -563,70 +585,70 @@ mod test { #[test] fn awaiting_act_one_to_awaiting_act_three_input_extra_bytes() { let test_ctx = TestCtx::new(); - let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); + let mut act1 = test_ctx.valid_act1; act1.extend_from_slice(&[1]); + let (act2, awaiting_act_three_state) = test_ctx.responder.next(&act1).unwrap(); - assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), ResponderAwaitingActThree(_))); + assert_eq!(act2.unwrap(), test_ctx.valid_act2); + assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_)); } - // Responder::AwaitingActOne -> Error (bad version byte) + // Responder::AwaitingActOne -> Error (input too small) + // RFC test vector: transport-responder act1 short read test #[test] - fn awaiting_act_one_to_awaiting_act_three_input_bad_version() { + fn awaiting_act_one_to_awaiting_act_three_input_too_small() { let test_ctx = TestCtx::new(); - let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); - // set version byte to 1 - act1[0] = 1; - - assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("unexpected version"))); + let act1 = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c").unwrap(); + assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("need at least 50 bytes"))) } - // Responder::AwaitingActOne -> Error (invalid hmac) + // Responder::AwaitingActOne -> Error (bad version byte) + // RFC test vector: transport-responder act1 bad version test #[test] - fn awaiting_act_one_to_awaiting_act_three_invalid_hmac() { + fn awaiting_act_one_to_awaiting_act_three_input_bad_version() { let test_ctx = TestCtx::new(); - // Modify the initiator to point to a different responder - let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); - // corrupt the ciphertext - act1[34] = 0; + let act1 = hex::decode("01036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap(); - assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("invalid hmac"))); + assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("unexpected version"))); } // Responder::AwaitingActOne -> Error (invalid remote ephemeral key) + // RFC test vector: transport-responder act1 bad key serialization test #[test] fn awaiting_act_one_to_awaiting_act_three_invalid_remote_ephemeral_key() { let test_ctx = TestCtx::new(); - // Modify the initiator to point to a different responder - let (mut act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); - // corrupt the ephemeral public key - act1[1] = 0; + let act1 = hex::decode("00046360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap(); assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("invalid remote ephemeral public key"))); } - // Responder::AwaitingActOne -> AwaitingActThree + // Responder::AwaitingActOne -> Error (invalid hmac) + // RFC test vector: transport-responder act1 bad MAC test #[test] - fn awaiting_act_one_to_awaiting_act_three() { + fn awaiting_act_one_to_awaiting_act_three_invalid_hmac() { let test_ctx = TestCtx::new(); - let (act1, _) = do_next_or_panic!(test_ctx.initiator, &[]); + let act1 = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6b").unwrap(); - assert_matches!(test_ctx.responder.next(&act1).unwrap(), (Some(_), ResponderAwaitingActThree(_))); + assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("invalid hmac"))); } // Initiator::AwaitingActTwo -> Complete + // RFC test vector: transport-initiator successful handshake #[test] fn awaiting_act_two_to_complete() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &test_ctx.valid_act2); - let remote_pubkey = if let (Some(_), Complete(Some((_, remote_pubkey)))) = awaiting_act_two_state.next(&act2).unwrap() { - remote_pubkey + let (conduit, remote_pubkey) = if let Complete(Some((conduit, remote_pubkey))) = complete_state { + (conduit, remote_pubkey) } else { panic!(); }; + assert_eq!(act3, test_ctx.valid_act3); assert_eq!(remote_pubkey, test_ctx.responder_static_public_key); + assert_eq!(0, conduit.decryptor.read_buffer_length()); } // Initiator::AwaitingActTwo -> Complete (with extra data) @@ -636,81 +658,81 @@ mod test { #[test] fn awaiting_act_two_to_complete_excess_bytes_are_in_conduit() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); + let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let mut act2 = test_ctx.valid_act2; act2.extend_from_slice(&[1; 100]); + let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); - let (_act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); - - let conduit = if let Complete(Some((conduit, _))) = complete_state { - conduit + let (conduit, remote_pubkey) = if let Complete(Some((conduit, remote_pubkey))) = complete_state { + (conduit, remote_pubkey) } else { panic!(); }; + assert_eq!(act3, test_ctx.valid_act3); + assert_eq!(remote_pubkey, test_ctx.responder_static_public_key); assert_eq!(100, conduit.decryptor.read_buffer_length()); } // Initiator::AwaitingActTwo -> Error (input too small) + // RFC test vector: transport-initiator act2 short read test #[test] fn awaiting_act_two_input_too_small() { let test_ctx = TestCtx::new(); let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let act2 = hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730").unwrap(); - assert_eq!(awaiting_act_two_state.next(&[]).err(), Some(String::from("need at least 50 bytes"))); + assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("need at least 50 bytes"))); } // Initiator::AwaitingActTwo -> Error (bad version byte) + // RFC test vector: transport-initiator act2 bad version test #[test] fn awaiting_act_two_bad_version_byte() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - // set invalid version byte - act2[0] = 1; + let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let act2 = hex::decode("0102466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap(); assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("unexpected version"))); } - // Initiator::AwaitingActTwo -> Error (invalid hmac) + // Initiator::AwaitingActTwo -> Error (invalid ephemeral public key) + // RFC test vector: transport-initiator act2 bad key serialization test #[test] - fn awaiting_act_two_invalid_hmac() { + fn awaiting_act_two_invalid_ephemeral_public_key() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - // corrupt the ciphertext - act2[34] = 0; + let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let act2 = hex::decode("0004466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap(); - assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("invalid hmac"))); + assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("invalid remote ephemeral public key"))); } - // Initiator::AwaitingActTwo -> Error (invalid ephemeral public key) + // Initiator::AwaitingActTwo -> Error (invalid hmac) + // RFC test vector: transport-initiator act2 bad MAC test #[test] - fn awaiting_act_two_invalid_ephemeral_public_key() { + fn awaiting_act_two_invalid_hmac() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (mut act2, _awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - // corrupt the ephemeral public key - act2[1] = 0; + let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); + let act2 = hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730af").unwrap(); - assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("invalid remote ephemeral public key"))); + assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("invalid hmac"))); } // Responder::AwaitingActThree -> Complete + // RFC test vector: transport-responder successful handshake #[test] fn awaiting_act_three_to_complete() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let (act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); - let remote_pubkey = if let (None, Complete(Some((_, remote_pubkey)))) = awaiting_act_three_state.next(&act3).unwrap() { - remote_pubkey + let (conduit, remote_pubkey) = if let (None, Complete(Some((conduit, remote_pubkey)))) = awaiting_act_three_state.next(&test_ctx.valid_act3).unwrap() { + (conduit, remote_pubkey) } else { panic!(); }; assert_eq!(remote_pubkey, test_ctx.initiator_public_key); + assert_eq!(0, conduit.decryptor.read_buffer_length()); } // Responder::AwaitingActThree -> None (with extra bytes) @@ -719,66 +741,71 @@ mod test { #[test] fn awaiting_act_three_excess_bytes_after_complete_are_in_conduit() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); + let mut act3 = test_ctx.valid_act3; act3.extend_from_slice(&[2; 100]); - let conduit = if let (_, Complete(Some((conduit, _)))) = awaiting_act_three_state.next(&act3).unwrap() { - conduit + let (conduit, remote_pubkey) = if let (None, Complete(Some((conduit, remote_pubkey)))) = awaiting_act_three_state.next(&act3).unwrap() { + (conduit, remote_pubkey) } else { panic!(); }; + assert_eq!(remote_pubkey, test_ctx.initiator_public_key); assert_eq!(100, conduit.decryptor.read_buffer_length()); } - // Responder::AwaitingActThree -> Error (input too small) + // Responder::AwaitingActThree -> Error (bad version bytes) + // RFC test vector: transport-responder act3 bad version test #[test] - fn awaiting_act_three_input_too_small() { + fn awaiting_act_three_bad_version_bytes() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let (act3, _complete) = do_next_or_panic!(awaiting_act_two_state, &act2); + let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); + let act3 = hex::decode("01b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap(); - assert_eq!(awaiting_act_three_state.next(&act3[..65]).err(), Some(String::from("need at least 66 bytes"))); + assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("unexpected version"))); } - // Responder::AwaitingActThree -> Error (bad version bytes) + // Responder::AwaitingActThree -> Error (input too small) + // RFC test vector: transport-responder act3 short read test #[test] - fn awaiting_act_three_bad_version_bytes() { + fn awaiting_act_three_input_too_small() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); - // set version byte to 1 - act3[0] = 1; + let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); + let act3 = hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139").unwrap(); - assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("unexpected version"))); + assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("need at least 66 bytes"))); } // Responder::AwaitingActThree -> Error (invalid hmac) + // RFC test vector: transport-responder act3 bad MAC for ciphertext test #[test] fn awaiting_act_three_invalid_hmac() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); - // corrupt encrypted pubkey - act3[1] = 1; + let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); + let act3 = hex::decode("00c9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap(); assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("invalid hmac"))); } + // Responder::AwaitingActThree -> Error (invalid remote_static_key) + // RFC test vector: transport-responder act3 bad rs test + #[test] + fn awaiting_act_three_invalid_rs() { + let test_ctx = TestCtx::new(); + let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); + let act3 = hex::decode("00bfe3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa2235536ad09a8ee351870c2bb7f78b754a26c6cef79a98d25139c856d7efd252c2ae73c").unwrap(); + + assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("invalid remote public key"))); + } + // Responder::AwaitingActThree -> Error (invalid tag hmac) + // RFC test vector: transport-responder act3 bad MAC test #[test] fn awaiting_act_three_invalid_tag_hmac() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &act1); - let (mut act3, _complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); - // corrupt tag - act3[50] = 1; + let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); + let act3 = hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139bb").unwrap(); assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("invalid hmac"))); } @@ -830,3 +857,4 @@ mod test { "00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba"); } } + From 8d46a1a180e50fdbe4ba6d6246268c5a18365f9e Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Fri, 21 Aug 2020 11:36:53 -0700 Subject: [PATCH 53/96] refactor: Simplify logic for init message sending The previous implementation used implementation details of the act byte returns from process_next_act() to determine whether or not to send an init message, but the Peer already has that information in it's outbound field. Use it instead to clean up the layering. --- lightning/src/ln/peers/handler.rs | 33 +++++++++++++------------------ 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index f2f3cf9bf66..841024024f6 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -118,7 +118,7 @@ enum PeerState { } enum PeerDataProcessingDecision { - CompleteHandshake(bool, PublicKey), + CompleteHandshake(PublicKey), Continue, Disconnect(PeerHandleError) } @@ -144,7 +144,6 @@ impl PeerState { Ok((response_vec_opt, conduit_and_remote_pubkey_opt)) => { // Any response generated by the handshake sequence is put into the response buffer - let requires_response = response_vec_opt.is_some(); if let Some(response_vec) = response_vec_opt { mutable_response_buffer.push_back(response_vec); } @@ -152,7 +151,7 @@ impl PeerState { // if process_act() returns the conduit and remote_pubkey the handshake // is complete if let Some((conduit, remote_pubkey)) = conduit_and_remote_pubkey_opt { - (Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(requires_response, remote_pubkey)) + (Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(remote_pubkey)) } else { (None, PeerDataProcessingDecision::Continue) } @@ -560,8 +559,6 @@ impl PeerManager panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => { - let mut send_init_message = false; - let data_processing_decision = peer.encryptor.process_peer_data(data, &mut peer.pending_outbound_buffer); match data_processing_decision { PeerDataProcessingDecision::Disconnect(e) => { @@ -569,10 +566,19 @@ impl PeerManager { - send_init_message = needs_to_send_init_message; + PeerDataProcessingDecision::CompleteHandshake(remote_pubkey) => { peer.their_node_id = Some(remote_pubkey); + if peer.outbound { + let mut features = InitFeatures::known(); + if !self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { + features.clear_initial_routing_sync(); + } + + let resp = msgs::Init { features }; + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); + } + // insert node id match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { hash_map::Entry::Occupied(_) => { @@ -586,20 +592,9 @@ impl PeerManager {} + _ => { } }; - if send_init_message { - let mut features = InitFeatures::known(); - if !self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.clear_initial_routing_sync(); - } - - let resp = msgs::Init { features }; - self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); - send_init_message = false - } - let mut received_messages = vec![]; if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { let encryptor = &mut conduit.encryptor; From 85f0238865a9f16ebd50c09374cc28a475bc22c3 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Fri, 21 Aug 2020 11:42:49 -0700 Subject: [PATCH 54/96] refactor: Clean up unused variable warnings --- lightning/src/ln/peers/conduit.rs | 19 +++---------------- lightning/src/ln/peers/handler.rs | 8 ++------ 2 files changed, 5 insertions(+), 22 deletions(-) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index c921e81935f..b9c1ac3d2ed 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -79,19 +79,6 @@ impl Conduit { self.decryptor.decrypt_single_message(new_data) } - /// Decrypt a message from the beginning of the provided buffer. Returns the consumed number of bytes. - fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { - self.decryptor.decrypt(buffer) - } - - fn increment_sending_nonce(&mut self) { - self.encryptor.increment_nonce() - } - - fn increment_receiving_nonce(&mut self) { - self.decryptor.increment_nonce() - } - fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { *nonce += 1; if *nonce == KEY_ROTATION_INDEX { @@ -247,7 +234,7 @@ mod tests { #[test] fn test_nonce_chaining() { - let (mut connected_peer, mut remote_peer) = setup_peers(); + let (mut connected_peer, _remote_peer) = setup_peers(); let message = hex::decode("68656c6c6f").unwrap(); let encrypted_message = connected_peer.encrypt(&message); @@ -261,7 +248,7 @@ mod tests { #[test] /// Based on RFC test vectors: https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#message-encryption-tests fn test_key_rotation() { - let (mut connected_peer, mut remote_peer) = setup_peers(); + let (mut connected_peer, _remote_peer) = setup_peers(); let message = hex::decode("68656c6c6f").unwrap(); let mut encrypted_messages: Vec> = Vec::new(); @@ -292,7 +279,7 @@ mod tests { for _ in 0..501 { // read two messages at once, filling buffer let mut current_encrypted_message = encrypted_messages.remove(0); - let mut next_encrypted_message = encrypted_messages.remove(0); + let next_encrypted_message = encrypted_messages.remove(0); current_encrypted_message.extend_from_slice(&next_encrypted_message); let decrypted_message = remote_peer.decrypt_single_message(Some(¤t_encrypted_message)).unwrap(); assert_eq!(decrypted_message, message); diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 841024024f6..828819781de 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -13,7 +13,6 @@ use ln::msgs; use ln::msgs::{ChannelMessageHandler, LightningError, RoutingMessageHandler}; use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; use util::ser::{VecWriter, Writeable}; -use ln::peer_channel_encryptor::{PeerChannelEncryptor,NextNoiseStep}; use ln::wire; use ln::wire::Encode; use util::byte_utils; @@ -136,7 +135,7 @@ impl PeerState { &mut PeerState::Authenticating(ref mut handshake) => { match handshake.process_act(data) { // Any errors originating from the handshake sequence result in Disconnect - Err(e) => { + Err(_e) => { (None, PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false })) }, // Otherwise, handshake may or may not be complete depending on whether or not @@ -597,10 +596,7 @@ impl PeerManager Date: Thu, 20 Aug 2020 19:53:12 -0700 Subject: [PATCH 55/96] refactor: Hide empty next() requirement inside PeerHandshake The fact that we have to call next() to generate act1 is an implementation detail of the handshake. Rename the old constructor to indicate that it creates and initializes the state and fix up the uses. --- lightning/src/ln/peers/handler.rs | 6 ++---- lightning/src/ln/peers/handshake/mod.rs | 23 ++++++++++++---------- lightning/src/ln/peers/handshake/states.rs | 4 +--- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 828819781de..d852fc0329f 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -356,9 +356,7 @@ impl PeerManager Result, PeerHandleError> { - let mut handshake = PeerHandshake::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); - let (act, ..) = handshake.process_act(&[]).unwrap(); - let res = act.unwrap(); + let (initial_bytes, handshake) = PeerHandshake::create_and_initialize_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { @@ -377,7 +375,7 @@ impl PeerManager Self { - Self { - state: Some(HandshakeState::new_initiator(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key)) - } + pub fn create_and_initialize_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> (Vec, Self) { + let state = HandshakeState::new_initiator(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key); + + // This transition does not have a failure path + let (response_vec_opt, next_state) = state.next(&[]).unwrap(); + (response_vec_opt.unwrap(), Self { state: Some(next_state) }) } /// Instantiate a new handshake in anticipation of a peer's first handshake act @@ -64,6 +66,7 @@ mod test { use bitcoin::secp256k1::key::{PublicKey, SecretKey}; struct TestCtx { + act1: Vec, outbound_handshake: PeerHandshake, outbound_static_public_key: PublicKey, inbound_handshake: PeerHandshake, @@ -82,10 +85,11 @@ mod test { let inbound_static_public_key = PublicKey::from_secret_key(&curve, &inbound_static_private_key); let inbound_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - let outbound_handshake = PeerHandshake::new_outbound(&outbound_static_private_key, &inbound_static_public_key, &outbound_ephemeral_private_key); + let (act1, outbound_handshake) = PeerHandshake::create_and_initialize_outbound(&outbound_static_private_key, &inbound_static_public_key, &outbound_ephemeral_private_key); let inbound_handshake = PeerHandshake::new_inbound(&inbound_static_private_key, &inbound_ephemeral_private_key); TestCtx { + act1, outbound_handshake, outbound_static_public_key, inbound_handshake, @@ -114,7 +118,7 @@ mod test { fn peer_handshake_new_outbound() { let test_ctx = TestCtx::new(); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::InitiatorStarting(_))); + assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::InitiatorAwaitingActTwo(_))); } // Default Inbound::AwaitingActOne @@ -133,8 +137,7 @@ mod test { #[test] fn full_sequence_sanity_test() { let mut test_ctx = TestCtx::new(); - let act1 = do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &act1); + let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &test_ctx.act1); let (act3, inbound_remote_pubkey) = if let (Some(act3), Some((_, remote_pubkey))) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { (act3, remote_pubkey) @@ -159,8 +162,8 @@ mod test { #[test] fn process_act_properly_updates_state() { let mut test_ctx = TestCtx::new(); - do_process_act_or_panic!(test_ctx.outbound_handshake, &[]); - assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::InitiatorAwaitingActTwo(_))); + do_process_act_or_panic!(test_ctx.inbound_handshake, &test_ctx.act1); + assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::ResponderAwaitingActThree(_))); } // Test that any errors from the state machine are passed back to the caller diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index d7de6845b71..8392dda3fff 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -560,10 +560,8 @@ mod test { #[test] fn starting_to_awaiting_act_two_extra_bytes() { let test_ctx = TestCtx::new(); - let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - assert_eq!(act1, test_ctx.valid_act1); - assert_matches!(awaiting_act_two_state, InitiatorAwaitingActTwo(_)); + assert_eq!(test_ctx.initiator.next(&[1]).err(), Some(String::from("first call for initiator must be empty"))); } // Responder::AwaitingActOne -> AwaitingActThree From a2828ab2b0112c8d92f397222b1d6c936d071df6 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 24 Aug 2020 09:41:05 -0700 Subject: [PATCH 56/96] refactor: Remove unnecessary copy_from_slice calls in states.rs Use the slice refs from the act array instead. --- lightning/src/ln/peers/handshake/states.rs | 27 ++++++---------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 8392dda3fff..e94554b0636 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -297,18 +297,12 @@ impl IHandshakeState for ResponderAwaitingActThreeState { let chaining_key = self.chaining_key; // 1. Read exactly 66 bytes from the network buffer - let mut act_three_bytes = [0u8; ACT_THREE_LENGTH]; - act_three_bytes.copy_from_slice(&read_buffer[..ACT_THREE_LENGTH]); - read_buffer.drain(..ACT_THREE_LENGTH); + let act_three_bytes: Vec = read_buffer.drain(..ACT_THREE_LENGTH).collect(); // 2. Parse the read message (m) into v, c, and t let version = act_three_bytes[0]; - - let mut tagged_encrypted_pubkey = [0u8; 49]; - tagged_encrypted_pubkey.copy_from_slice(&act_three_bytes[1..50]); - - let mut chacha_tag = [0u8; 16]; - chacha_tag.copy_from_slice(&act_three_bytes[50..66]); + let tagged_encrypted_pubkey = &act_three_bytes[1..50]; + let chacha_tag = &act_three_bytes[50..66]; // 3. If v is an unrecognized handshake version, then the responder MUST abort the connection attempt. if version != 0 { @@ -318,9 +312,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // 4. rs = decryptWithAD(temp_k2, 1, h, c) let remote_pubkey_vec = chacha::decrypt(&temporary_key, 1, &hash, &tagged_encrypted_pubkey)?; - let mut initiator_pubkey_bytes = [0u8; 33]; - initiator_pubkey_bytes.copy_from_slice(remote_pubkey_vec.as_slice()); - let initiator_pubkey = if let Ok(public_key) = PublicKey::from_slice(&initiator_pubkey_bytes) { + let initiator_pubkey = if let Ok(public_key) = PublicKey::from_slice(remote_pubkey_vec.as_slice()) { public_key } else { return Err("invalid remote public key".to_string()); @@ -419,24 +411,19 @@ fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, return Err("need at least 50 bytes".to_string()); } - let mut act_bytes = [0u8; ACT_ONE_TWO_LENGTH]; - act_bytes.copy_from_slice(&read_buffer[..ACT_ONE_TWO_LENGTH]); - read_buffer.drain(..ACT_ONE_TWO_LENGTH); + let act_bytes: Vec = read_buffer.drain(..ACT_ONE_TWO_LENGTH).collect(); // 2.Parse the read message (m) into v, re, and c let version = act_bytes[0]; + let ephemeral_public_key_bytes = &act_bytes[1..34]; + let chacha_tag = &act_bytes[34..50]; - let mut ephemeral_public_key_bytes = [0u8; 33]; - ephemeral_public_key_bytes.copy_from_slice(&act_bytes[1..34]); let ephemeral_public_key = if let Ok(public_key) = PublicKey::from_slice(&ephemeral_public_key_bytes) { public_key } else { return Err("invalid remote ephemeral public key".to_string()); }; - let mut chacha_tag = [0u8; 16]; - chacha_tag.copy_from_slice(&act_bytes[34..50]); - // 3. If v is an unrecognized handshake version, then the responder MUST abort the connection attempt if version != 0 { // this should not crash the process, hence no panic From db6bf0afa0a40fc431c0d44c249ad1653d587efe Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sat, 22 Aug 2020 18:49:10 -0700 Subject: [PATCH 57/96] tests: Add new fuzz testing for PeerHandshake Write a new fuzz test for the PeerHandshake module that is able to generate failure paths that occur after a partial handshake sequence has been completed. To enable this, a new testing object FuzzGen has been introduced that can deterministically generate bytes and bools based on the random fuzz input. These building blocks are enough for the test code to generates different execution paths and complete partial phases of the handshake protocol before generating an error. When going through a test cycle where the handshake completes, it will also verify that the initiator and responder can communicate successfully through the returned conduits sending variable length data and validating the contents. --- fuzz/src/peer_crypt.rs | 331 +++++++++++++++++++++++++++++++++-------- 1 file changed, 273 insertions(+), 58 deletions(-) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index 0d200d83a19..37703e4265d 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -1,78 +1,238 @@ -use lightning::ln::peer_channel_encryptor::PeerChannelEncryptor; +use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey,SecretKey}; - +use lightning::ln::peers::conduit::Conduit; +use lightning::ln::peers::handshake::PeerHandshake; use utils::test_logger; -#[inline] -fn slice_to_be16(v: &[u8]) -> u16 { - ((v[0] as u16) << 8*1) | - ((v[1] as u16) << 8*0) +// Test structure used to generate "random" values based on input data. It is used throughout +// the various test cases to send random messages between nodes and to ensure the code does not fail +// unexpectedly. +pub struct FuzzGen<'a> { + read_pos: usize, + data: &'a [u8], } -#[inline] -pub fn do_test(data: &[u8]) { - let mut read_pos = 0; - macro_rules! get_slice { - ($len: expr) => { - { - let slice_len = $len as usize; - if data.len() < read_pos + slice_len { - return; - } - read_pos += slice_len; - &data[read_pos - slice_len..read_pos] +impl<'a> FuzzGen<'a> { + pub fn new(data: &'a [u8]) -> Self { + Self { + read_pos: 0, + data + } + } + + pub fn generate_bytes(&mut self, num: usize) -> Result<&'a [u8], String> { + if self.data.len() < self.read_pos + num { + return Err("out of bytes".to_string()); + } + + self.read_pos += num; + Ok(&self.data[self.read_pos - num..self.read_pos]) + } + + pub fn generate_secret_key(&mut self) -> Result { + // Loop through the input 32 bytes at a time until a valid + // secret key can be created or we run out of bytes + loop { + match SecretKey::from_slice(self.generate_bytes(32)?) { + Ok(key) => { return Ok(key) }, + _ => {} } } } - let our_network_key = match SecretKey::from_slice(get_slice!(32)) { - Ok(key) => key, - Err(_) => return, + pub fn generate_bool(&mut self) -> Result { + let next_byte = self.generate_bytes(1)?; + Ok(next_byte[0] & 1 == 1) + } +} + +struct TestCtx { + initiator_static_public_key: PublicKey, + initiator_handshake: PeerHandshake, + responder_static_public_key: PublicKey, + responder_handshake: PeerHandshake, + act1: Vec +} + +impl TestCtx { + fn make(generator: &mut FuzzGen) -> Result { + let curve = secp256k1::Secp256k1::new(); + + // Generate needed keys for successful handshake + let initiator_static_private_key = generator.generate_secret_key()?; + let initiator_static_public_key = PublicKey::from_secret_key(&curve, &initiator_static_private_key); + let initiator_ephemeral_private_key = generator.generate_secret_key()?; + let responder_static_private_key = generator.generate_secret_key()?; + let responder_static_public_key = PublicKey::from_secret_key(&curve, &responder_static_private_key); + let responder_ephemeral_private_key = generator.generate_secret_key()?; + + let (act1, initiator_handshake) = PeerHandshake::create_and_initialize_outbound(&initiator_static_private_key, &responder_static_public_key, &initiator_ephemeral_private_key); + let responder_handshake = PeerHandshake::new_inbound(&responder_static_private_key, &responder_ephemeral_private_key); + + Ok(TestCtx { + initiator_static_public_key, + initiator_handshake, + responder_static_public_key, + responder_handshake, + act1 + }) + } +} + +// Common test function that sends encrypted messages between two conduits until the source data +// runs out. +#[inline] +fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, responder_conduit: &mut Conduit) -> Result<(), String> { + // Keep sending messages back and forth until the input data is consumed + loop { + // Randomly generate message length + let msg_len_raw = generator.generate_bytes(1)?; + let msg_len = msg_len_raw[0] as usize; + + // Randomly generate message + let sender_unencrypted_msg = generator.generate_bytes(msg_len)?; + + // randomly choose sender of message + let receiver_unencrypted_msg = if generator.generate_bool()? { + let encrypted_msg = initiator_conduit.encrypt(sender_unencrypted_msg); + responder_conduit.decrypt_single_message(Some(&encrypted_msg)) + } else { + let encrypted_msg = responder_conduit.encrypt(sender_unencrypted_msg); + initiator_conduit.decrypt_single_message(Some(&encrypted_msg)) + }; + + assert_eq!(sender_unencrypted_msg, receiver_unencrypted_msg.unwrap().as_slice()); + } +} + +// This test completes a valid handshake based on "random" private keys and then sends variable +// length encrypted messages between two conduits to validate that they can communicate. +#[inline] +fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), String> { + let mut test_ctx = TestCtx::make(generator)?; + + // The handshake should complete with any valid private keys + let act2 = test_ctx.responder_handshake.process_act(&test_ctx.act1).unwrap().0.unwrap(); + let (act3, (mut initiator_conduit, responder_pubkey)) = match test_ctx.initiator_handshake.process_act(&act2) { + Ok((Some(act3), Some((conduit, remote_pubkey)))) => { + (act3, (conduit, remote_pubkey)) + } + _ => panic!("handshake failed") }; - let ephemeral_key = match SecretKey::from_slice(get_slice!(32)) { - Ok(key) => key, - Err(_) => return, + + let (mut responder_conduit, initiator_pubkey) = match test_ctx.responder_handshake.process_act(&act3) { + Ok((None, Some((conduit, remote_pubkey)))) => { + (conduit, remote_pubkey) + } + _ => panic!("handshake failed") }; - let mut crypter = if get_slice!(1)[0] != 0 { - let their_pubkey = match PublicKey::from_slice(get_slice!(33)) { - Ok(key) => key, - Err(_) => return, - }; - let mut crypter = PeerChannelEncryptor::new_outbound(their_pubkey, ephemeral_key); - crypter.get_act_one(); - match crypter.process_act_two(get_slice!(50), &our_network_key) { - Ok(_) => {}, - Err(_) => return, + // The handshake should complete with each peer knowing the static_public_key of the remote peer + assert_eq!(initiator_pubkey, test_ctx.initiator_static_public_key); + assert_eq!(responder_pubkey, test_ctx.responder_static_public_key); + + // The nodes should be able to communicate over the conduit + do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit)?; + + unreachable!(); +} + +// This test variant goes through the peer handshake between the initiator and responder with +// "random" failures to verify that nothing panics. +// In the event of an error from process_act() we validate that the input data was generated +// randomly to ensure real act generation still produces valid transitions. +#[inline] +fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), String> { + let mut test_ctx = TestCtx::make(generator)?; + let mut used_generated_data = false; + + // Possibly generate bad data for act1 and ensure that the responder does not panic + let mut act1 = test_ctx.act1; + if generator.generate_bool()? { + act1 = (generator.generate_bytes(50)?).to_vec(); + used_generated_data = true; + } + + let mut act2 = match test_ctx.responder_handshake.process_act(&act1) { + Ok((Some(act2), None)) => { + act2 } - assert!(crypter.is_ready_for_encryption()); - crypter - } else { - let mut crypter = PeerChannelEncryptor::new_inbound(&our_network_key); - match crypter.process_act_one_with_keys(get_slice!(50), &our_network_key, ephemeral_key) { - Ok(_) => {}, - Err(_) => return, + Err(_) => { + assert!(used_generated_data); + return Err("generated expected failure with bad data".to_string()); } - match crypter.process_act_three(get_slice!(66)) { - Ok(_) => {}, - Err(_) => return, + _ => panic!("responder required to output act bytes and no conduit/pubkey") + }; + + // Possibly generate bad data for act2 and ensure that the initiator does not panic + if generator.generate_bool()? { + act2 = (generator.generate_bytes(50)?).to_vec(); + used_generated_data = true; + } + + let (mut act3, (mut initiator_conduit, responder_pubkey)) = match test_ctx.initiator_handshake.process_act(&act2) { + Ok((Some(act3), Some((conduit, remote_pubkey)))) => { + (act3, (conduit, remote_pubkey)) } - assert!(crypter.is_ready_for_encryption()); - crypter + Err(_) => { + assert!(used_generated_data); + return Err("generated expected failure with bad data".to_string()); + } + _ => panic!("initiator required to output act bytes and no conduit/pubkey") }; - loop { - if get_slice!(1)[0] == 0 { - crypter.encrypt_message(get_slice!(slice_to_be16(get_slice!(2)))); - } else { - let len = match crypter.decrypt_length_header(get_slice!(16+2)) { - Ok(len) => len, - Err(_) => return, - }; - match crypter.decrypt_message(get_slice!(len as usize + 16)) { - Ok(_) => {}, - Err(_) => return, - } + + // Possibly generate bad data for act3 and ensure that the responder does not panic + if generator.generate_bool()? { + act3 = (generator.generate_bytes(66)?).to_vec(); + used_generated_data = true; + } + + let (mut responder_conduit, initiator_pubkey) = match test_ctx.responder_handshake.process_act(&act3) { + Ok((None, Some((conduit, remote_pubkey)))) => { + (conduit, remote_pubkey) + } + Err(_) => { + // extremely unlikely we randomly generate a correct act3, but if so.. reset this + assert!(used_generated_data); + return Err("generated expected failure with bad data".to_string()); + }, + _ => panic!("responder required to output conduit/remote pubkey and no act bytes") + }; + + // The handshake should complete with each peer knowing the static_public_key of the remote peer + if initiator_pubkey != test_ctx.initiator_static_public_key { + assert!(used_generated_data); + return Ok(()); + } + if responder_pubkey != test_ctx.responder_static_public_key { + assert!(used_generated_data); + return Ok(()); + } + + // The nodes should be able to communicate over the conduit + do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit)?; + + unreachable!(); +} + +#[inline] +fn do_test(data: &[u8]) { + let mut generator = FuzzGen::new(data); + + // Based on a "random" bool, decide which test variant to run + let do_valid_handshake = match generator.generate_bool() { + Ok(value) => { value }, + _ => { return } + }; + + if do_valid_handshake { + match do_completed_handshake_test(&mut generator) { + _ => {} + } + } else { + match do_handshake_test(&mut generator) { + _ => {} } } } @@ -85,3 +245,58 @@ pub fn peer_crypt_test(data: &[u8], _out: Out) { pub extern "C" fn peer_crypt_run(data: *const u8, datalen: usize) { do_test(unsafe { std::slice::from_raw_parts(data, datalen) }); } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn data_generator_empty() { + let mut generator = FuzzGen::new(&[]); + assert_eq!(generator.generate_bool().err(), Some("out of bytes".to_string())); + } + + #[test] + fn data_generator_bool_true() { + let mut generator = FuzzGen::new(&[1]); + assert!(generator.generate_bool().unwrap()); + } + + #[test] + fn data_generator_bool_false() { + let mut generator = FuzzGen::new(&[0]); + assert!(!generator.generate_bool().unwrap()); + } + + #[test] + fn data_generator_bool_then_error() { + let mut generator = FuzzGen::new(&[1]); + assert!(generator.generate_bool().unwrap()); + assert_eq!(generator.generate_bool().err(), Some("out of bytes".to_string())); + } + + #[test] + fn data_generator_bytes_too_many() { + let mut generator = FuzzGen::new(&[1, 2, 3, 4]); + assert_eq!(generator.generate_bytes(5).err(), Some("out of bytes".to_string())); + } + + #[test] + fn data_generator_bytes() { + let input = [1, 2, 3, 4]; + let mut generator = FuzzGen::new(&input); + let result = generator.generate_bytes(4).unwrap(); + assert_eq!(result, input); + } + + #[test] + fn data_generator_bytes_sequential() { + let input = [1, 2, 3, 4]; + let mut generator = FuzzGen::new(&input); + let result = generator.generate_bytes(2).unwrap(); + assert_eq!(result, &input[..2]); + let result = generator.generate_bytes(2).unwrap(); + assert_eq!(result, &input[2..]); + assert_eq!(generator.generate_bytes(1).err(), Some("out of bytes".to_string())); + } +} \ No newline at end of file From c049519def23a26147c3ea10c75d04ac8cc2b32b Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sat, 22 Aug 2020 19:46:45 -0700 Subject: [PATCH 58/96] delete: Remove peer_channel_encryptor.rs Functionality moved to: - peers/handshake/mod.rs - peers/handshake/states.rs - peers/conduit.rs Fuzz testing rewritten here: - fuzz/src/peer_crypt.rs --- lightning/src/ln/mod.rs | 5 - lightning/src/ln/peer_channel_encryptor.rs | 716 --------------------- lightning/src/ln/peers/conduit.rs | 1 + lightning/src/ln/peers/mod.rs | 12 +- 4 files changed, 11 insertions(+), 723 deletions(-) delete mode 100644 lightning/src/ln/peer_channel_encryptor.rs diff --git a/lightning/src/ln/mod.rs b/lightning/src/ln/mod.rs index eea78b62a06..82f01c4121b 100644 --- a/lightning/src/ln/mod.rs +++ b/lightning/src/ln/mod.rs @@ -17,11 +17,6 @@ pub mod chan_utils; pub mod features; pub(crate) mod onchaintx; -#[cfg(feature = "fuzztarget")] -pub mod peer_channel_encryptor; -#[cfg(not(feature = "fuzztarget"))] -pub(crate) mod peer_channel_encryptor; - mod channel; mod onion_utils; mod wire; diff --git a/lightning/src/ln/peer_channel_encryptor.rs b/lightning/src/ln/peer_channel_encryptor.rs deleted file mode 100644 index 152426577ad..00000000000 --- a/lightning/src/ln/peer_channel_encryptor.rs +++ /dev/null @@ -1,716 +0,0 @@ -use ln::msgs::LightningError; -use ln::msgs; - -use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine}; -use bitcoin::hashes::sha256::Hash as Sha256; - -use bitcoin::secp256k1::Secp256k1; -use bitcoin::secp256k1::key::{PublicKey,SecretKey}; -use bitcoin::secp256k1::ecdh::SharedSecret; -use bitcoin::secp256k1; - -use util::chacha20poly1305rfc::ChaCha20Poly1305RFC; -use util::byte_utils; - -// Sha256("Noise_XK_secp256k1_ChaChaPoly_SHA256") -const NOISE_CK: [u8; 32] = [0x26, 0x40, 0xf5, 0x2e, 0xeb, 0xcd, 0x9e, 0x88, 0x29, 0x58, 0x95, 0x1c, 0x79, 0x42, 0x50, 0xee, 0xdb, 0x28, 0x00, 0x2c, 0x05, 0xd7, 0xdc, 0x2e, 0xa0, 0xf1, 0x95, 0x40, 0x60, 0x42, 0xca, 0xf1]; -// Sha256(NOISE_CK || "lightning") -const NOISE_H: [u8; 32] = [0xd1, 0xfb, 0xf6, 0xde, 0xe4, 0xf6, 0x86, 0xf1, 0x32, 0xfd, 0x70, 0x2c, 0x4a, 0xbf, 0x8f, 0xba, 0x4b, 0xb4, 0x20, 0xd8, 0x9d, 0x2a, 0x04, 0x8a, 0x3c, 0x4f, 0x4c, 0x09, 0x2e, 0x37, 0xb6, 0x76]; - -pub enum NextNoiseStep { - ActOne, - ActTwo, - ActThree, - NoiseComplete, -} - -#[derive(PartialEq)] -enum NoiseStep { - PreActOne, - PostActOne, - PostActTwo, - // When done swap noise_state for NoiseState::Finished -} - -struct BidirectionalNoiseState { - h: [u8; 32], - ck: [u8; 32], -} -enum DirectionalNoiseState { - Outbound { - ie: SecretKey, - }, - Inbound { - ie: Option, // filled in if state >= PostActOne - re: Option, // filled in if state >= PostActTwo - temp_k2: Option<[u8; 32]>, // filled in if state >= PostActTwo - } -} -enum NoiseState { - InProgress { - state: NoiseStep, - directional_state: DirectionalNoiseState, - bidirectional_state: BidirectionalNoiseState, - }, - Finished { - sk: [u8; 32], - sn: u64, - sck: [u8; 32], - rk: [u8; 32], - rn: u64, - rck: [u8; 32], - } -} - -pub struct PeerChannelEncryptor { - secp_ctx: Secp256k1, - their_node_id: Option, // filled in for outbound, or inbound after noise_state is Finished - - noise_state: NoiseState, -} - -impl PeerChannelEncryptor { - pub fn new_outbound(their_node_id: PublicKey, ephemeral_key: SecretKey) -> PeerChannelEncryptor { - let secp_ctx = Secp256k1::signing_only(); - - let mut sha = Sha256::engine(); - sha.input(&NOISE_H); - sha.input(&their_node_id.serialize()[..]); - let h = Sha256::from_engine(sha).into_inner(); - - PeerChannelEncryptor { - their_node_id: Some(their_node_id), - secp_ctx: secp_ctx, - noise_state: NoiseState::InProgress { - state: NoiseStep::PreActOne, - directional_state: DirectionalNoiseState::Outbound { - ie: ephemeral_key, - }, - bidirectional_state: BidirectionalNoiseState { - h: h, - ck: NOISE_CK, - }, - } - } - } - - pub fn new_inbound(our_node_secret: &SecretKey) -> PeerChannelEncryptor { - let secp_ctx = Secp256k1::signing_only(); - - let mut sha = Sha256::engine(); - sha.input(&NOISE_H); - let our_node_id = PublicKey::from_secret_key(&secp_ctx, our_node_secret); - sha.input(&our_node_id.serialize()[..]); - let h = Sha256::from_engine(sha).into_inner(); - - PeerChannelEncryptor { - their_node_id: None, - secp_ctx: secp_ctx, - noise_state: NoiseState::InProgress { - state: NoiseStep::PreActOne, - directional_state: DirectionalNoiseState::Inbound { - ie: None, - re: None, - temp_k2: None, - }, - bidirectional_state: BidirectionalNoiseState { - h: h, - ck: NOISE_CK, - }, - } - } - } - - #[inline] - fn encrypt_with_ad(res: &mut[u8], n: u64, key: &[u8; 32], h: &[u8], plaintext: &[u8]) { - let mut nonce = [0; 12]; - nonce[4..].copy_from_slice(&byte_utils::le64_to_array(n)); - - let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h); - let mut tag = [0; 16]; - chacha.encrypt(plaintext, &mut res[0..plaintext.len()], &mut tag); - res[plaintext.len()..].copy_from_slice(&tag); - } - - #[inline] - fn decrypt_with_ad(res: &mut[u8], n: u64, key: &[u8; 32], h: &[u8], cyphertext: &[u8]) -> Result<(), LightningError> { - let mut nonce = [0; 12]; - nonce[4..].copy_from_slice(&byte_utils::le64_to_array(n)); - - let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce, h); - if !chacha.decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]) { - return Err(LightningError{err: "Bad MAC", action: msgs::ErrorAction::DisconnectPeer{ msg: None }}); - } - Ok(()) - } - - fn hkdf_extract_expand(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) { - let mut hmac = HmacEngine::::new(salt); - hmac.input(ikm); - let prk = Hmac::from_engine(hmac).into_inner(); - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&[1; 1]); - let t1 = Hmac::from_engine(hmac).into_inner(); - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&t1); - hmac.input(&[2; 1]); - (t1, Hmac::from_engine(hmac).into_inner()) - } - - #[inline] - fn hkdf(state: &mut BidirectionalNoiseState, ss: SharedSecret) -> [u8; 32] { - let (t1, t2) = Self::hkdf_extract_expand(&state.ck, &ss[..]); - state.ck = t1; - t2 - } - - #[inline] - fn outbound_noise_act(secp_ctx: &Secp256k1, state: &mut BidirectionalNoiseState, our_key: &SecretKey, their_key: &PublicKey) -> ([u8; 50], [u8; 32]) { - let our_pub = PublicKey::from_secret_key(secp_ctx, &our_key); - - let mut sha = Sha256::engine(); - sha.input(&state.h); - sha.input(&our_pub.serialize()[..]); - state.h = Sha256::from_engine(sha).into_inner(); - - let ss = SharedSecret::new(&their_key, &our_key); - let temp_k = PeerChannelEncryptor::hkdf(state, ss); - - let mut res = [0; 50]; - res[1..34].copy_from_slice(&our_pub.serialize()[..]); - PeerChannelEncryptor::encrypt_with_ad(&mut res[34..], 0, &temp_k, &state.h, &[0; 0]); - - let mut sha = Sha256::engine(); - sha.input(&state.h); - sha.input(&res[34..]); - state.h = Sha256::from_engine(sha).into_inner(); - - (res, temp_k) - } - - #[inline] - fn inbound_noise_act(state: &mut BidirectionalNoiseState, act: &[u8], our_key: &SecretKey) -> Result<(PublicKey, [u8; 32]), LightningError> { - assert_eq!(act.len(), 50); - - if act[0] != 0 { - return Err(LightningError{err: "Unknown handshake version number", action: msgs::ErrorAction::DisconnectPeer{ msg: None }}); - } - - let their_pub = match PublicKey::from_slice(&act[1..34]) { - Err(_) => return Err(LightningError{err: "Invalid public key", action: msgs::ErrorAction::DisconnectPeer{ msg: None }}), - Ok(key) => key, - }; - - let mut sha = Sha256::engine(); - sha.input(&state.h); - sha.input(&their_pub.serialize()[..]); - state.h = Sha256::from_engine(sha).into_inner(); - - let ss = SharedSecret::new(&their_pub, &our_key); - let temp_k = PeerChannelEncryptor::hkdf(state, ss); - - let mut dec = [0; 0]; - PeerChannelEncryptor::decrypt_with_ad(&mut dec, 0, &temp_k, &state.h, &act[34..])?; - - let mut sha = Sha256::engine(); - sha.input(&state.h); - sha.input(&act[34..]); - state.h = Sha256::from_engine(sha).into_inner(); - - Ok((their_pub, temp_k)) - } - - pub fn get_act_one(&mut self) -> [u8; 50] { - match self.noise_state { - NoiseState::InProgress { ref mut state, ref directional_state, ref mut bidirectional_state } => - match directional_state { - &DirectionalNoiseState::Outbound { ref ie } => { - if *state != NoiseStep::PreActOne { - panic!("Requested act at wrong step"); - } - - let (res, _) = PeerChannelEncryptor::outbound_noise_act(&self.secp_ctx, bidirectional_state, &ie, &self.their_node_id.unwrap()); - *state = NoiseStep::PostActOne; - res - }, - _ => panic!("Wrong direction for act"), - }, - _ => panic!("Cannot get act one after noise handshake completes"), - } - } - - pub fn process_act_one_with_keys(&mut self, act_one: &[u8], our_node_secret: &SecretKey, our_ephemeral: SecretKey) -> Result<[u8; 50], LightningError> { - assert_eq!(act_one.len(), 50); - - match self.noise_state { - NoiseState::InProgress { ref mut state, ref mut directional_state, ref mut bidirectional_state } => - match directional_state { - &mut DirectionalNoiseState::Inbound { ref mut ie, ref mut re, ref mut temp_k2 } => { - if *state != NoiseStep::PreActOne { - panic!("Requested act at wrong step"); - } - - let (their_pub, _) = PeerChannelEncryptor::inbound_noise_act(bidirectional_state, act_one, &our_node_secret)?; - ie.get_or_insert(their_pub); - - re.get_or_insert(our_ephemeral); - - let (res, temp_k) = PeerChannelEncryptor::outbound_noise_act(&self.secp_ctx, bidirectional_state, &re.unwrap(), &ie.unwrap()); - *temp_k2 = Some(temp_k); - *state = NoiseStep::PostActTwo; - Ok(res) - }, - _ => panic!("Wrong direction for act"), - }, - _ => panic!("Cannot get act one after noise handshake completes"), - } - } - - pub fn process_act_two(&mut self, act_two: &[u8], our_node_secret: &SecretKey) -> Result<([u8; 66], PublicKey), LightningError> { - assert_eq!(act_two.len(), 50); - - let final_hkdf; - let ck; - let res: [u8; 66] = match self.noise_state { - NoiseState::InProgress { ref state, ref directional_state, ref mut bidirectional_state } => - match directional_state { - &DirectionalNoiseState::Outbound { ref ie } => { - if *state != NoiseStep::PostActOne { - panic!("Requested act at wrong step"); - } - - let (re, temp_k2) = PeerChannelEncryptor::inbound_noise_act(bidirectional_state, act_two, &ie)?; - - let mut res = [0; 66]; - let our_node_id = PublicKey::from_secret_key(&self.secp_ctx, &our_node_secret); - - PeerChannelEncryptor::encrypt_with_ad(&mut res[1..50], 1, &temp_k2, &bidirectional_state.h, &our_node_id.serialize()[..]); - - let mut sha = Sha256::engine(); - sha.input(&bidirectional_state.h); - sha.input(&res[1..50]); - bidirectional_state.h = Sha256::from_engine(sha).into_inner(); - - let ss = SharedSecret::new(&re, our_node_secret); - let temp_k = PeerChannelEncryptor::hkdf(bidirectional_state, ss); - - PeerChannelEncryptor::encrypt_with_ad(&mut res[50..], 0, &temp_k, &bidirectional_state.h, &[0; 0]); - final_hkdf = Self::hkdf_extract_expand(&bidirectional_state.ck, &[0; 0]); - ck = bidirectional_state.ck.clone(); - res - }, - _ => panic!("Wrong direction for act"), - }, - _ => panic!("Cannot get act one after noise handshake completes"), - }; - - let (sk, rk) = final_hkdf; - self.noise_state = NoiseState::Finished { - sk: sk, - sn: 0, - sck: ck.clone(), - rk: rk, - rn: 0, - rck: ck, - }; - - Ok((res, self.their_node_id.unwrap().clone())) - } - - pub fn process_act_three(&mut self, act_three: &[u8]) -> Result { - assert_eq!(act_three.len(), 66); - - let final_hkdf; - let ck; - match self.noise_state { - NoiseState::InProgress { ref state, ref directional_state, ref mut bidirectional_state } => - match directional_state { - &DirectionalNoiseState::Inbound { ie: _, ref re, ref temp_k2 } => { - if *state != NoiseStep::PostActTwo { - panic!("Requested act at wrong step"); - } - if act_three[0] != 0 { - return Err(LightningError{err: "Unknown handshake version number", action: msgs::ErrorAction::DisconnectPeer{ msg: None }}); - } - - let mut their_node_id = [0; 33]; - PeerChannelEncryptor::decrypt_with_ad(&mut their_node_id, 1, &temp_k2.unwrap(), &bidirectional_state.h, &act_three[1..50])?; - self.their_node_id = Some(match PublicKey::from_slice(&their_node_id) { - Ok(key) => key, - Err(_) => return Err(LightningError{err: "Bad node_id from peer", action: msgs::ErrorAction::DisconnectPeer{ msg: None }}), - }); - - let mut sha = Sha256::engine(); - sha.input(&bidirectional_state.h); - sha.input(&act_three[1..50]); - bidirectional_state.h = Sha256::from_engine(sha).into_inner(); - - let ss = SharedSecret::new(&self.their_node_id.unwrap(), &re.unwrap()); - let temp_k = PeerChannelEncryptor::hkdf(bidirectional_state, ss); - - PeerChannelEncryptor::decrypt_with_ad(&mut [0; 0], 0, &temp_k, &bidirectional_state.h, &act_three[50..])?; - final_hkdf = Self::hkdf_extract_expand(&bidirectional_state.ck, &[0; 0]); - ck = bidirectional_state.ck.clone(); - }, - _ => panic!("Wrong direction for act"), - }, - _ => panic!("Cannot get act one after noise handshake completes"), - } - - let (rk, sk) = final_hkdf; - self.noise_state = NoiseState::Finished { - sk: sk, - sn: 0, - sck: ck.clone(), - rk: rk, - rn: 0, - rck: ck, - }; - - Ok(self.their_node_id.unwrap().clone()) - } - - /// Encrypts the given message, returning the encrypted version - /// panics if msg.len() > 65535 or Noise handshake has not finished. - pub fn encrypt_message(&mut self, msg: &[u8]) -> Vec { - if msg.len() > 65535 { - panic!("Attempted to encrypt message longer than 65535 bytes!"); - } - - let mut res = Vec::with_capacity(msg.len() + 16*2 + 2); - res.resize(msg.len() + 16*2 + 2, 0); - - match self.noise_state { - NoiseState::Finished { ref mut sk, ref mut sn, ref mut sck, rk: _, rn: _, rck: _ } => { - if *sn >= 1000 { - let (new_sck, new_sk) = Self::hkdf_extract_expand(sck, sk); - *sck = new_sck; - *sk = new_sk; - *sn = 0; - } - - Self::encrypt_with_ad(&mut res[0..16+2], *sn, sk, &[0; 0], &byte_utils::be16_to_array(msg.len() as u16)); - *sn += 1; - - Self::encrypt_with_ad(&mut res[16+2..], *sn, sk, &[0; 0], msg); - *sn += 1; - }, - _ => panic!("Tried to encrypt a message prior to noise handshake completion"), - } - - res - } - - /// Decrypts a message length header from the remote peer. - /// panics if noise handshake has not yet finished or msg.len() != 18 - pub fn decrypt_length_header(&mut self, msg: &[u8]) -> Result { - assert_eq!(msg.len(), 16+2); - - match self.noise_state { - NoiseState::Finished { sk: _, sn: _, sck: _, ref mut rk, ref mut rn, ref mut rck } => { - if *rn >= 1000 { - let (new_rck, new_rk) = Self::hkdf_extract_expand(rck, rk); - *rck = new_rck; - *rk = new_rk; - *rn = 0; - } - - let mut res = [0; 2]; - Self::decrypt_with_ad(&mut res, *rn, rk, &[0; 0], msg)?; - *rn += 1; - Ok(byte_utils::slice_to_be16(&res)) - }, - _ => panic!("Tried to encrypt a message prior to noise handshake completion"), - } - } - - /// Decrypts the given message. - /// panics if msg.len() > 65535 + 16 - pub fn decrypt_message(&mut self, msg: &[u8]) -> Result, LightningError> { - if msg.len() > 65535 + 16 { - panic!("Attempted to encrypt message longer than 65535 bytes!"); - } - - match self.noise_state { - NoiseState::Finished { sk: _, sn: _, sck: _, ref rk, ref mut rn, rck: _ } => { - let mut res = Vec::with_capacity(msg.len() - 16); - res.resize(msg.len() - 16, 0); - Self::decrypt_with_ad(&mut res[..], *rn, rk, &[0; 0], msg)?; - *rn += 1; - - Ok(res) - }, - _ => panic!("Tried to encrypt a message prior to noise handshake completion"), - } - } - - pub fn get_noise_step(&self) -> NextNoiseStep { - match self.noise_state { - NoiseState::InProgress {ref state, ..} => { - match state { - &NoiseStep::PreActOne => NextNoiseStep::ActOne, - &NoiseStep::PostActOne => NextNoiseStep::ActTwo, - &NoiseStep::PostActTwo => NextNoiseStep::ActThree, - } - }, - NoiseState::Finished {..} => NextNoiseStep::NoiseComplete, - } - } - - pub fn is_ready_for_encryption(&self) -> bool { - match self.noise_state { - NoiseState::InProgress {..} => { false }, - NoiseState::Finished {..} => { true } - } - } -} - -#[cfg(test)] -mod tests { - use bitcoin::secp256k1::key::{PublicKey,SecretKey}; - - use hex; - - use ln::peer_channel_encryptor::{PeerChannelEncryptor,NoiseState}; - - fn get_outbound_peer_for_initiator_test_vectors() -> PeerChannelEncryptor { - let their_node_id = PublicKey::from_slice(&hex::decode("028d7500dd4c12685d1f568b4c2b5048e8534b873319f3a8daa612b469132ec7f7").unwrap()[..]).unwrap(); - - let mut outbound_peer = PeerChannelEncryptor::new_outbound(their_node_id, SecretKey::from_slice(&hex::decode("1212121212121212121212121212121212121212121212121212121212121212").unwrap()[..]).unwrap()); - assert_eq!(outbound_peer.get_act_one()[..], hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap()[..]); - outbound_peer - } - - #[test] - fn noise_initiator_test_vectors() { - let our_node_id = SecretKey::from_slice(&hex::decode("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(); - - { - // transport-initiator successful handshake - let mut outbound_peer = get_outbound_peer_for_initiator_test_vectors(); - - let act_two = hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap().to_vec(); - assert_eq!(outbound_peer.process_act_two(&act_two[..], &our_node_id).unwrap().0[..], hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap()[..]); - - match outbound_peer.noise_state { - NoiseState::Finished { sk, sn, sck, rk, rn, rck } => { - assert_eq!(sk, hex::decode("969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9").unwrap()[..]); - assert_eq!(sn, 0); - assert_eq!(sck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - assert_eq!(rk, hex::decode("bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442").unwrap()[..]); - assert_eq!(rn, 0); - assert_eq!(rck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - }, - _ => panic!() - } - } - { - // transport-initiator act2 short read test - // Can't actually test this cause process_act_two requires you pass the right length! - } - { - // transport-initiator act2 bad version test - let mut outbound_peer = get_outbound_peer_for_initiator_test_vectors(); - - let act_two = hex::decode("0102466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap().to_vec(); - assert!(outbound_peer.process_act_two(&act_two[..], &our_node_id).is_err()); - } - - { - // transport-initiator act2 bad key serialization test - let mut outbound_peer = get_outbound_peer_for_initiator_test_vectors(); - - let act_two = hex::decode("0004466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap().to_vec(); - assert!(outbound_peer.process_act_two(&act_two[..], &our_node_id).is_err()); - } - - { - // transport-initiator act2 bad MAC test - let mut outbound_peer = get_outbound_peer_for_initiator_test_vectors(); - - let act_two = hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730af").unwrap().to_vec(); - assert!(outbound_peer.process_act_two(&act_two[..], &our_node_id).is_err()); - } - } - - #[test] - fn noise_responder_test_vectors() { - let our_node_id = SecretKey::from_slice(&hex::decode("2121212121212121212121212121212121212121212121212121212121212121").unwrap()[..]).unwrap(); - let our_ephemeral = SecretKey::from_slice(&hex::decode("2222222222222222222222222222222222222222222222222222222222222222").unwrap()[..]).unwrap(); - - { - // transport-responder successful handshake - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert_eq!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).unwrap()[..], hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap()[..]); - - let act_three = hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap().to_vec(); - // test vector doesn't specify the initiator static key, but it's the same as the one - // from transport-initiator successful handshake - assert_eq!(inbound_peer.process_act_three(&act_three[..]).unwrap().serialize()[..], hex::decode("034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa").unwrap()[..]); - - match inbound_peer.noise_state { - NoiseState::Finished { sk, sn, sck, rk, rn, rck } => { - assert_eq!(sk, hex::decode("bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442").unwrap()[..]); - assert_eq!(sn, 0); - assert_eq!(sck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - assert_eq!(rk, hex::decode("969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9").unwrap()[..]); - assert_eq!(rn, 0); - assert_eq!(rck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - }, - _ => panic!() - } - } - { - // transport-responder act1 short read test - // Can't actually test this cause process_act_one requires you pass the right length! - } - { - // transport-responder act1 bad version test - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("01036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).is_err()); - } - { - // transport-responder act1 bad key serialization test - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one =hex::decode("00046360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).is_err()); - } - { - // transport-responder act1 bad MAC test - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6b").unwrap().to_vec(); - assert!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).is_err()); - } - { - // transport-responder act3 bad version test - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert_eq!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).unwrap()[..], hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap()[..]); - - let act_three = hex::decode("01b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap().to_vec(); - assert!(inbound_peer.process_act_three(&act_three[..]).is_err()); - } - { - // transport-responder act3 short read test - // Can't actually test this cause process_act_three requires you pass the right length! - } - { - // transport-responder act3 bad MAC for ciphertext test - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert_eq!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).unwrap()[..], hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap()[..]); - - let act_three = hex::decode("00c9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap().to_vec(); - assert!(inbound_peer.process_act_three(&act_three[..]).is_err()); - } - { - // transport-responder act3 bad rs test - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert_eq!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).unwrap()[..], hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap()[..]); - - let act_three = hex::decode("00bfe3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa2235536ad09a8ee351870c2bb7f78b754a26c6cef79a98d25139c856d7efd252c2ae73c").unwrap().to_vec(); - assert!(inbound_peer.process_act_three(&act_three[..]).is_err()); - } - { - // transport-responder act3 bad MAC test - let mut inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert_eq!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).unwrap()[..], hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap()[..]); - - let act_three = hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139bb").unwrap().to_vec(); - assert!(inbound_peer.process_act_three(&act_three[..]).is_err()); - } - } - - - #[test] - fn message_encryption_decryption_test_vectors() { - // We use the same keys as the initiator and responder test vectors, so we copy those tests - // here and use them to encrypt. - let mut outbound_peer = get_outbound_peer_for_initiator_test_vectors(); - - { - let our_node_id = SecretKey::from_slice(&hex::decode("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(); - - let act_two = hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap().to_vec(); - assert_eq!(outbound_peer.process_act_two(&act_two[..], &our_node_id).unwrap().0[..], hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap()[..]); - - match outbound_peer.noise_state { - NoiseState::Finished { sk, sn, sck, rk, rn, rck } => { - assert_eq!(sk, hex::decode("969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9").unwrap()[..]); - assert_eq!(sn, 0); - assert_eq!(sck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - assert_eq!(rk, hex::decode("bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442").unwrap()[..]); - assert_eq!(rn, 0); - assert_eq!(rck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - }, - _ => panic!() - } - } - - let mut inbound_peer; - - { - // transport-responder successful handshake - let our_node_id = SecretKey::from_slice(&hex::decode("2121212121212121212121212121212121212121212121212121212121212121").unwrap()[..]).unwrap(); - let our_ephemeral = SecretKey::from_slice(&hex::decode("2222222222222222222222222222222222222222222222222222222222222222").unwrap()[..]).unwrap(); - - inbound_peer = PeerChannelEncryptor::new_inbound(&our_node_id); - - let act_one = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap().to_vec(); - assert_eq!(inbound_peer.process_act_one_with_keys(&act_one[..], &our_node_id, our_ephemeral.clone()).unwrap()[..], hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap()[..]); - - let act_three = hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139ba").unwrap().to_vec(); - // test vector doesn't specify the initiator static key, but it's the same as the one - // from transport-initiator successful handshake - assert_eq!(inbound_peer.process_act_three(&act_three[..]).unwrap().serialize()[..], hex::decode("034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa").unwrap()[..]); - - match inbound_peer.noise_state { - NoiseState::Finished { sk, sn, sck, rk, rn, rck } => { - assert_eq!(sk, hex::decode("bb9020b8965f4df047e07f955f3c4b88418984aadc5cdb35096b9ea8fa5c3442").unwrap()[..]); - assert_eq!(sn, 0); - assert_eq!(sck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - assert_eq!(rk, hex::decode("969ab31b4d288cedf6218839b27a3e2140827047f2c0f01bf5c04435d43511a9").unwrap()[..]); - assert_eq!(rn, 0); - assert_eq!(rck, hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap()[..]); - }, - _ => panic!() - } - } - - for i in 0..1005 { - let msg = [0x68, 0x65, 0x6c, 0x6c, 0x6f]; - let res = outbound_peer.encrypt_message(&msg); - assert_eq!(res.len(), 5 + 2*16 + 2); - - let len_header = res[0..2+16].to_vec(); - assert_eq!(inbound_peer.decrypt_length_header(&len_header[..]).unwrap() as usize, msg.len()); - assert_eq!(inbound_peer.decrypt_message(&res[2+16..]).unwrap()[..], msg[..]); - - if i == 0 { - assert_eq!(res, hex::decode("cf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95").unwrap()); - } else if i == 1 { - assert_eq!(res, hex::decode("72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1").unwrap()); - } else if i == 500 { - assert_eq!(res, hex::decode("178cb9d7387190fa34db9c2d50027d21793c9bc2d40b1e14dcf30ebeeeb220f48364f7a4c68bf8").unwrap()); - } else if i == 501 { - assert_eq!(res, hex::decode("1b186c57d44eb6de4c057c49940d79bb838a145cb528d6e8fd26dbe50a60ca2c104b56b60e45bd").unwrap()); - } else if i == 1000 { - assert_eq!(res, hex::decode("4a2f3cc3b5e78ddb83dcb426d9863d9d9a723b0337c89dd0b005d89f8d3c05c52b76b29b740f09").unwrap()); - } else if i == 1001 { - assert_eq!(res, hex::decode("2ecd8c8a5629d0d02ab457a0fdd0f7b90a192cd46be5ecb6ca570bfc5e268338b1a16cf4ef2d36").unwrap()); - } - } - } -} diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index b9c1ac3d2ed..2414f067fec 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -75,6 +75,7 @@ impl Conduit { /// only the first message will be returned, and the rest stored in the internal buffer. /// If a message pending in the buffer still hasn't been decrypted, that message will be /// returned in lieu of anything new, even if new data is provided. + #[cfg(any(test, feature = "fuzztarget"))] pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Option> { self.decryptor.decrypt_single_message(new_data) } diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index f8082c50f10..072950c0dba 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -4,7 +4,15 @@ //! Conduit enables message encryption and decryption, and automatically handles key rotation. mod chacha; -pub mod conduit; -pub mod handshake; pub mod handler; mod hkdf; + +#[cfg(feature = "fuzztarget")] +pub mod conduit; +#[cfg(not(feature = "fuzztarget"))] +mod conduit; + +#[cfg(feature = "fuzztarget")] +pub mod handshake; +#[cfg(not(feature = "fuzztarget"))] +mod handshake; From 076a8bfa1f7121203e2e0cf89696ba587e04b608 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sun, 23 Aug 2020 21:09:41 -0700 Subject: [PATCH 59/96] fix: Allow partial act messages to be received Fix regression introduced in eb6a371 that would error and subsequently cause a disconnect if a partial act was sent to the state machine, even if future calls could be added to the read buffer to create a valid act. Add appropriate unit tests and update fuzz testing to send partial acts some of the time. --- lightning/src/ln/peers/handshake/mod.rs | 6 +- lightning/src/ln/peers/handshake/states.rs | 93 +++++++++++++++++----- 2 files changed, 76 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 35d5b9627d8..3bf47ebb60a 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -173,7 +173,8 @@ mod test { #[test] fn errors_properly_returned() { let mut test_ctx = TestCtx::new(); - assert_matches!(test_ctx.inbound_handshake.process_act(&[]).err(), Some(_)); + let invalid_act1 = [0; 50]; + assert_matches!(test_ctx.inbound_handshake.process_act(&invalid_act1).err(), Some(_)); } // Test that any use of the PeerHandshake after returning an error panics @@ -181,7 +182,8 @@ mod test { #[should_panic(expected = "called `Option::unwrap()` on a `None` value")] fn use_after_error_panics() { let mut test_ctx = TestCtx::new(); - assert_matches!(test_ctx.inbound_handshake.process_act(&[]).err(), Some(_)); + let invalid_act1 = [0; 50]; + assert_matches!(test_ctx.inbound_handshake.process_act(&invalid_act1).err(), Some(_)); test_ctx.inbound_handshake.process_act(&[]).unwrap(); } } diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index e94554b0636..8aba9fe20c1 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -181,6 +181,22 @@ impl IHandshakeState for ResponderAwaitingActOneState { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); + // In the event of a partial fill, stay in the same state and wait for more data + if read_buffer.len() < ACT_ONE_TWO_LENGTH { + return Ok(( + None, + HandshakeState::ResponderAwaitingActOne(Self { + responder_static_private_key: self.responder_static_private_key, + responder_ephemeral_private_key: self.responder_ephemeral_private_key, + responder_ephemeral_public_key: self.responder_ephemeral_public_key, + chaining_key: self.chaining_key, + hash: self.hash, + read_buffer + }) + )); + } + + let hash = self.hash; let responder_static_private_key = self.responder_static_private_key; let chaining_key = self.chaining_key; @@ -222,6 +238,22 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); + // In the event of a partial fill, stay in the same state and wait for more data + if read_buffer.len() < ACT_ONE_TWO_LENGTH { + return Ok(( + None, + HandshakeState::InitiatorAwaitingActTwo(Self { + initiator_static_private_key: self.initiator_static_private_key, + initiator_static_public_key: self.initiator_static_public_key, + initiator_ephemeral_private_key: self.initiator_ephemeral_private_key, + responder_static_public_key: self.responder_static_public_key, + chaining_key: self.chaining_key, + hash: self.hash, + read_buffer + }) + )); + } + let initiator_static_private_key = self.initiator_static_private_key; let initiator_static_public_key = self.initiator_static_public_key; let initiator_ephemeral_private_key = self.initiator_ephemeral_private_key; @@ -287,8 +319,18 @@ impl IHandshakeState for ResponderAwaitingActThreeState { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); + // In the event of a partial fill, stay in the same state and wait for more data if read_buffer.len() < ACT_THREE_LENGTH { - return Err("need at least 66 bytes".to_string()); + return Ok(( + None, + HandshakeState::ResponderAwaitingActThree(Self { + hash: self.hash, + responder_ephemeral_private_key: self.responder_ephemeral_private_key, + chaining_key: self.chaining_key, + temporary_key: self.temporary_key, + read_buffer + }) + )); } let hash = self.hash; @@ -407,10 +449,6 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, chaining_key: ChainingKey, hash: Sha256) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), String> { // 1. Read exactly 50 bytes from the network buffer - if read_buffer.len() < ACT_ONE_TWO_LENGTH { - return Err("need at least 50 bytes".to_string()); - } - let act_bytes: Vec = read_buffer.drain(..ACT_ONE_TWO_LENGTH).collect(); // 2.Parse the read message (m) into v, re, and c @@ -503,9 +541,9 @@ mod test { let responder = ResponderAwaitingActOneState::new(responder_static_private_key, responder_ephemeral_private_key); TestCtx { - initiator: HandshakeState::InitiatorStarting(initiator), + initiator: InitiatorStarting(initiator), initiator_public_key, - responder: HandshakeState::ResponderAwaitingActOne(responder), + responder: ResponderAwaitingActOne(responder), responder_static_public_key, valid_act1: hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c6a").unwrap(), valid_act2: hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730ae").unwrap(), @@ -565,8 +603,6 @@ mod test { // Responder::AwaitingActOne -> AwaitingActThree // TODO: Should this fail since we don't expect data > ACT_ONE_TWO_LENGTH and likely indicates // a bad peer? - // TODO: Should the behavior be changed to handle act1 data that is striped across multiple - // next() calls? #[test] fn awaiting_act_one_to_awaiting_act_three_input_extra_bytes() { let test_ctx = TestCtx::new(); @@ -578,13 +614,18 @@ mod test { assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_)); } - // Responder::AwaitingActOne -> Error (input too small) + // Responder::AwaitingActOne -> AwaitingActThree (segmented calls) // RFC test vector: transport-responder act1 short read test + // Divergence from RFC tests due to not reading directly from the socket (partial message OK) #[test] - fn awaiting_act_one_to_awaiting_act_three_input_too_small() { + fn awaiting_act_one_to_awaiting_act_three_segmented() { let test_ctx = TestCtx::new(); - let act1 = hex::decode("00036360e856310ce5d294e8be33fc807077dc56ac80d95d9cd4ddbd21325eff73f70df6086551151f58b8afe6c195782c").unwrap(); - assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("need at least 50 bytes"))) + let act1_partial1 = &test_ctx.valid_act1[..25]; + let act1_partial2 = &test_ctx.valid_act1[25..]; + + let next_state = test_ctx.responder.next(&act1_partial1).unwrap(); + assert_matches!(next_state, (None, ResponderAwaitingActOne(_))); + assert_matches!(next_state.1.next(&act1_partial2).unwrap(), (Some(_), ResponderAwaitingActThree(_))); } // Responder::AwaitingActOne -> Error (bad version byte) @@ -659,15 +700,20 @@ mod test { assert_eq!(100, conduit.decryptor.read_buffer_length()); } - // Initiator::AwaitingActTwo -> Error (input too small) + // Initiator::AwaitingActTwo -> Complete (segmented calls) // RFC test vector: transport-initiator act2 short read test + // Divergence from RFC tests due to not reading directly from the socket (partial message OK) #[test] - fn awaiting_act_two_input_too_small() { + fn awaiting_act_two_to_complete_segmented() { let test_ctx = TestCtx::new(); let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let act2 = hex::decode("0002466d7fcae563e5cb09a0d1870bb580344804617879a14949cf22285f1bae3f276e2470b93aac583c9ef6eafca3f730").unwrap(); - assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("need at least 50 bytes"))); + let act2_partial1 = &test_ctx.valid_act2[..25]; + let act2_partial2 = &test_ctx.valid_act2[25..]; + + let next_state = awaiting_act_two_state.next(&act2_partial1).unwrap(); + assert_matches!(next_state, (None, InitiatorAwaitingActTwo(_))); + assert_matches!(next_state.1.next(&act2_partial2).unwrap(), (Some(_), Complete(_))); } // Initiator::AwaitingActTwo -> Error (bad version byte) @@ -751,15 +797,20 @@ mod test { assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("unexpected version"))); } - // Responder::AwaitingActThree -> Error (input too small) + // Responder::AwaitingActThree -> Complete (segmented calls) // RFC test vector: transport-responder act3 short read test + // Divergence from RFC tests due to not reading directly from the socket (partial message OK) #[test] - fn awaiting_act_three_input_too_small() { + fn awaiting_act_three_to_complete_segmented() { let test_ctx = TestCtx::new(); let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); - let act3 = hex::decode("00b9e3a702e93e3a9948c2ed6e5fd7590a6e1c3a0344cfc9d5b57357049aa22355361aa02e55a8fc28fef5bd6d71ad0c38228dc68b1c466263b47fdf31e560e139").unwrap(); - assert_eq!(awaiting_act_three_state.next(&act3).err(), Some(String::from("need at least 66 bytes"))); + let act3_partial1 = &test_ctx.valid_act3[..35]; + let act3_partial2 = &test_ctx.valid_act3[35..]; + + let next_state = awaiting_act_three_state.next(&act3_partial1).unwrap(); + assert_matches!(next_state, (None, ResponderAwaitingActThree(_))); + assert_matches!(next_state.1.next(&act3_partial2), Ok((None, Complete(_)))); } // Responder::AwaitingActThree -> Error (invalid hmac) From e7fbab934b8ed6f5c51383b751196aae4c7e8f79 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 24 Aug 2020 16:52:15 -0700 Subject: [PATCH 60/96] fix: Conduit::Decryptor should not panic on decryption failure introduced in eb6a371 On decryption failure, the Decryptor should return an error to the caller so it can disconnect instead of panicking. Implement this behavior by plumbing Result through the iterator code path and adding the appropriate tests and comments. --- lightning/src/ln/peers/conduit.rs | 157 ++++++++++++++++++++++++++---- lightning/src/ln/peers/handler.rs | 70 ++++++++----- 2 files changed, 185 insertions(+), 42 deletions(-) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 2414f067fec..ac2f251e8ee 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -33,13 +33,29 @@ pub(super) struct Decryptor { pending_message_length: Option, read_buffer: Option>, + poisoned: bool, // signal an error has occurred so None is returned on iteration after failure } impl Iterator for Decryptor { - type Item = Vec; + type Item = Result>, String>; fn next(&mut self) -> Option { - self.decrypt_single_message(None) + if self.poisoned { + return None; + } + + match self.decrypt_single_message(None) { + Ok(Some(result)) => { + Some(Ok(Some(result))) + }, + Ok(None) => { + None + } + Err(e) => { + self.poisoned = true; + Some(Err(e)) + } + } } } @@ -57,7 +73,8 @@ impl Conduit { receiving_chaining_key: chaining_key, receiving_nonce: 0, read_buffer: None, - pending_message_length: None + pending_message_length: None, + poisoned: false } } } @@ -76,8 +93,8 @@ impl Conduit { /// If a message pending in the buffer still hasn't been decrypted, that message will be /// returned in lieu of anything new, even if new data is provided. #[cfg(any(test, feature = "fuzztarget"))] - pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Option> { - self.decryptor.decrypt_single_message(new_data) + pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Result>, String> { + Ok(self.decryptor.decrypt_single_message(new_data)?) } fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { @@ -126,7 +143,7 @@ impl Decryptor { /// only the first message will be returned, and the rest stored in the internal buffer. /// If a message pending in the buffer still hasn't been decrypted, that message will be /// returned in lieu of anything new, even if new data is provided. - pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Option> { + pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Result>, String> { let mut read_buffer = if let Some(buffer) = self.read_buffer.take() { buffer } else { @@ -137,25 +154,25 @@ impl Decryptor { read_buffer.extend_from_slice(data); } - let (current_message, offset) = self.decrypt(&read_buffer[..]); + let (current_message, offset) = self.decrypt(&read_buffer[..])?; read_buffer.drain(..offset); // drain the read buffer self.read_buffer = Some(read_buffer); // assign the new value to the built-in buffer - current_message + Ok(current_message) } - fn decrypt(&mut self, buffer: &[u8]) -> (Option>, usize) { + fn decrypt(&mut self, buffer: &[u8]) -> Result<(Option>, usize), String> { let message_length = if let Some(length) = self.pending_message_length { // we have already decrypted the header length } else { if buffer.len() < TAGGED_MESSAGE_LENGTH_HEADER_SIZE { // A message must be at least 18 bytes (2 for encrypted length, 16 for the tag) - return (None, 0); + return Ok((None, 0)); } let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; let mut length_bytes = [0u8; MESSAGE_LENGTH_HEADER_SIZE]; - length_bytes.copy_from_slice(&chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length).unwrap()); + length_bytes.copy_from_slice(&chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length)?); self.increment_nonce(); @@ -167,18 +184,18 @@ impl Decryptor { if buffer.len() < message_end_index { self.pending_message_length = Some(message_length); - return (None, 0); + return Ok((None, 0)); } self.pending_message_length = None; let encrypted_message = &buffer[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..message_end_index]; - let message = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_message).unwrap(); + let message = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_message)?; self.increment_nonce(); - (Some(message), message_end_index) + Ok((Some(message), message_end_index)) } fn increment_nonce(&mut self) { @@ -229,7 +246,7 @@ mod tests { let encrypted_message = connected_peer.encrypt(&message); assert_eq!(encrypted_message.len(), 2 + 16 + 16); - let decrypted_message = remote_peer.decrypt_single_message(Some(&encrypted_message)).unwrap(); + let decrypted_message = remote_peer.decrypt_single_message(Some(&encrypted_message)).unwrap().unwrap(); assert_eq!(decrypted_message, vec![]); } @@ -282,14 +299,120 @@ mod tests { let mut current_encrypted_message = encrypted_messages.remove(0); let next_encrypted_message = encrypted_messages.remove(0); current_encrypted_message.extend_from_slice(&next_encrypted_message); - let decrypted_message = remote_peer.decrypt_single_message(Some(¤t_encrypted_message)).unwrap(); + let decrypted_message = remote_peer.decrypt_single_message(Some(¤t_encrypted_message)).unwrap().unwrap(); assert_eq!(decrypted_message, message); } for _ in 0..501 { // decrypt messages directly from buffer without adding to it - let decrypted_message = remote_peer.decrypt_single_message(None).unwrap(); + let decrypted_message = remote_peer.decrypt_single_message(None).unwrap().unwrap(); assert_eq!(decrypted_message, message); } } + + // Decryption errors should result in Err + #[test] + fn decryption_failure_errors() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let encrypted = remote_peer.encrypt(&[1]); + + connected_peer.decryptor.receiving_key = [0; 32]; + assert_eq!(connected_peer.decrypt_single_message(Some(&encrypted)), Err("invalid hmac".to_string())); + } + + // Test next()::None + #[test] + fn decryptor_iterator_empty() { + let (mut connected_peer, _) = setup_peers(); + + assert_eq!(connected_peer.decryptor.next(), None); + } + + // Test next() -> next()::None + #[test] + fn decryptor_iterator_one_item_valid() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let encrypted = remote_peer.encrypt(&[1]); + connected_peer.read(&encrypted); + + assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); + assert_eq!(connected_peer.decryptor.next(), None); + } + + // Test next()::err -> next()::None + #[test] + fn decryptor_iterator_error() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let encrypted = remote_peer.encrypt(&[1]); + connected_peer.read(&encrypted); + + connected_peer.decryptor.receiving_key = [0; 32]; + assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); + assert_eq!(connected_peer.decryptor.next(), None); + } + + // Test next()::Some -> next()::err -> next()::None + #[test] + fn decryptor_iterator_error_after_success() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let encrypted = remote_peer.encrypt(&[1]); + connected_peer.read(&encrypted); + let encrypted = remote_peer.encrypt(&[2]); + connected_peer.read(&encrypted); + + assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); + connected_peer.decryptor.receiving_key = [0; 32]; + assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); + assert_eq!(connected_peer.decryptor.next(), None); + } + + // Test that next()::Some -> next()::err -> next()::None + // Error should poison decryptor + #[test] + fn decryptor_iterator_next_after_error_returns_none() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let encrypted = remote_peer.encrypt(&[1]); + connected_peer.read(&encrypted); + let encrypted = remote_peer.encrypt(&[2]); + connected_peer.read(&encrypted); + let encrypted = remote_peer.encrypt(&[3]); + connected_peer.read(&encrypted); + + // Get one valid value + assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); + let valid_receiving_key = connected_peer.decryptor.receiving_key; + + // Corrupt the receiving key and ensure we get a failure + connected_peer.decryptor.receiving_key = [0; 32]; + assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); + + // Restore the receiving key, do a read and ensure None is returned (poisoned) + connected_peer.decryptor.receiving_key = valid_receiving_key; + assert_eq!(connected_peer.decryptor.next(), None); + } + + // Test next()::Some -> next()::err -> read() -> next()::None + // Error should poison decryptor even after future reads + #[test] + fn decryptor_iterator_read_next_after_error_returns_none() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + let encrypted = remote_peer.encrypt(&[1]); + connected_peer.read(&encrypted); + let encrypted = remote_peer.encrypt(&[2]); + connected_peer.read(&encrypted); + + // Get one valid value + assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); + let valid_receiving_key = connected_peer.decryptor.receiving_key; + + // Corrupt the receiving key and ensure we get a failure + connected_peer.decryptor.receiving_key = [0; 32]; + assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); + + // Restore the receiving key, do a read and ensure None is returned (poisoned) + let encrypted = remote_peer.encrypt(&[3]); + connected_peer.read(&encrypted); + connected_peer.decryptor.receiving_key = valid_receiving_key; + assert_eq!(connected_peer.decryptor.next(), None); + } } \ No newline at end of file diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index d852fc0329f..9c0b11394a0 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -594,33 +594,53 @@ impl PeerManager x, - Err(e) => { - match e { - msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(self.logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); - continue; - } - msgs::DecodeError::InvalidValue => { - log_debug!(self.logger, "Got an invalid value while deserializing message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ShortRead => { - log_debug!(self.logger, "Deserialization failed due to shortness of message"); - return Err(PeerHandleError { no_connection_possible: false }); + // Using Iterators that can error requires special handling + // The item returned from next() has type Option, String>> + // The Some wrapper is stripped for each item inside the loop + // There are 3 valid match cases: + // 1) Some(Ok(Some(msg_data))) => Indicates a valid decrypted msg accessed via msg_data + // 2) Some(Err(_)) => Indicates an error during decryption that should be handled + // 3) None -> Indicates there were no messages available to decrypt + // Invalid Cases + // 1) Some(Ok(None)) => Translated to None case above so users of iterators can stop correctly + for msg_data_result in &mut conduit.decryptor { + match msg_data_result { + Ok(Some(msg_data)) => { + let mut reader = ::std::io::Cursor::new(&msg_data[..]); + let message_result = wire::read(&mut reader); + let message = match message_result { + Ok(x) => x, + Err(e) => { + match e { + msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::UnknownRequiredFeature => { + log_debug!(self.logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + continue; + } + msgs::DecodeError::InvalidValue => { + log_debug!(self.logger, "Got an invalid value while deserializing message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ShortRead => { + log_debug!(self.logger, "Deserialization failed due to shortness of message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), + } } - msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), - } - } - }; + }; - received_messages.push(message); + received_messages.push(message); + }, + Err(e) => { + log_trace!(self.logger, "Message decryption failed due to: {}", e); + return Err(PeerHandleError { no_connection_possible: false }); + } + Ok(None) => { + panic!("Invalid behavior. Conduit iterator should never return this match.") + } + } } } From 4f1e6a9536d13c7a4dd056485598ad914cc1fae0 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 24 Aug 2020 14:11:52 -0700 Subject: [PATCH 61/96] test: Update handshake fuzz test to cover more cases Enhanced the fuzz testing to simulate more test cases: * Valid or random act data * Optionally sending garbage data along with act * Optionally sending act data in multiple segments Found regression introduced in eb6a371 relating to the Conduit panicking during an hmac failure. --- fuzz/src/peer_crypt.rs | 334 ++++++++++++++++++++++++++++++++--------- 1 file changed, 264 insertions(+), 70 deletions(-) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index 37703e4265d..d83857c957e 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -1,3 +1,6 @@ +use std::cmp; +use std::{error, fmt}; + use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey,SecretKey}; @@ -14,39 +17,56 @@ pub struct FuzzGen<'a> { } impl<'a> FuzzGen<'a> { - pub fn new(data: &'a [u8]) -> Self { + fn new(data: &'a [u8]) -> Self { Self { read_pos: 0, data } } - pub fn generate_bytes(&mut self, num: usize) -> Result<&'a [u8], String> { + fn generate_bytes(&mut self, num: usize) -> Result<&'a [u8], GeneratorFinishedError> { if self.data.len() < self.read_pos + num { - return Err("out of bytes".to_string()); + return Err(GeneratorFinishedError { }); } self.read_pos += num; Ok(&self.data[self.read_pos - num..self.read_pos]) } - pub fn generate_secret_key(&mut self) -> Result { + fn generate_secret_key(&mut self) -> Result { // Loop through the input 32 bytes at a time until a valid // secret key can be created or we run out of bytes loop { match SecretKey::from_slice(self.generate_bytes(32)?) { Ok(key) => { return Ok(key) }, - _ => {} + _ => { } } } } - pub fn generate_bool(&mut self) -> Result { + fn generate_bool(&mut self) -> Result { let next_byte = self.generate_bytes(1)?; Ok(next_byte[0] & 1 == 1) } } +#[derive(PartialEq)] +struct GeneratorFinishedError { } + +impl fmt::Debug for GeneratorFinishedError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter.write_str("Generator out of bytes") + } +} +impl fmt::Display for GeneratorFinishedError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { + formatter.write_str("Generator out of bytes") + } +} +impl error::Error for GeneratorFinishedError { + fn description(&self) -> &str { "Generator out of bytes" } +} + struct TestCtx { initiator_static_public_key: PublicKey, initiator_handshake: PeerHandshake, @@ -56,7 +76,7 @@ struct TestCtx { } impl TestCtx { - fn make(generator: &mut FuzzGen) -> Result { + fn make(generator: &mut FuzzGen) -> Result { let curve = secp256k1::Secp256k1::new(); // Generate needed keys for successful handshake @@ -83,7 +103,7 @@ impl TestCtx { // Common test function that sends encrypted messages between two conduits until the source data // runs out. #[inline] -fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, responder_conduit: &mut Conduit) -> Result<(), String> { +fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, responder_conduit: &mut Conduit, failures_expected: bool) -> Result<(), GeneratorFinishedError> { // Keep sending messages back and forth until the input data is consumed loop { // Randomly generate message length @@ -96,10 +116,20 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re // randomly choose sender of message let receiver_unencrypted_msg = if generator.generate_bool()? { let encrypted_msg = initiator_conduit.encrypt(sender_unencrypted_msg); - responder_conduit.decrypt_single_message(Some(&encrypted_msg)) + if let Ok(msg) = responder_conduit.decrypt_single_message(Some(&encrypted_msg)) { + msg + } else { + assert!(failures_expected); + return Ok(()); + } } else { let encrypted_msg = responder_conduit.encrypt(sender_unencrypted_msg); - initiator_conduit.decrypt_single_message(Some(&encrypted_msg)) + if let Ok(msg) = initiator_conduit.decrypt_single_message(Some(&encrypted_msg)) { + msg + } else { + assert!(failures_expected); + return Ok(()); + } }; assert_eq!(sender_unencrypted_msg, receiver_unencrypted_msg.unwrap().as_slice()); @@ -109,7 +139,7 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re // This test completes a valid handshake based on "random" private keys and then sends variable // length encrypted messages between two conduits to validate that they can communicate. #[inline] -fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), String> { +fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedError> { let mut test_ctx = TestCtx::make(generator)?; // The handshake should complete with any valid private keys @@ -132,10 +162,37 @@ fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), String> { assert_eq!(initiator_pubkey, test_ctx.initiator_static_public_key); assert_eq!(responder_pubkey, test_ctx.responder_static_public_key); - // The nodes should be able to communicate over the conduit - do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit)?; + // The nodes should be able to communicate over the conduit. + do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit, false) +} - unreachable!(); +// Either returns (act, false) or (random_bytes, true) where random_bytes is the same len as act +fn maybe_generate_bad_act(generator: &mut FuzzGen, act: Vec) -> Result<(Vec, bool), GeneratorFinishedError> { + if generator.generate_bool()? { + Ok(((generator.generate_bytes(act.len())?).to_vec(), true)) + } else { + Ok((act, false)) + } +} + +// Add between 0..15 bytes of garbage to a vec and returns whether or not it added bytes +fn maybe_add_garbage(generator: &mut FuzzGen, input: &mut Vec) -> Result { + let garbage_amount = (generator.generate_bytes(1)?)[0] >> 4; + + if garbage_amount != 0 { + input.extend(generator.generate_bytes(garbage_amount as usize)?); + Ok(true) + } else { + Ok(false) + } +} + +// Splits a Vec into between 1..7 chunks returning a Vec of slices into the original data +fn split_vec<'a>(generator: &mut FuzzGen, input: &'a Vec) -> Result, GeneratorFinishedError> { + let num_chunks = cmp::max(1, ((generator.generate_bytes(1)?)[0] as u8) >> 5) as usize; + let chunk_size = input.len() / num_chunks; + + Ok(input.chunks(chunk_size).collect()) } // This test variant goes through the peer handshake between the initiator and responder with @@ -143,62 +200,108 @@ fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), String> { // In the event of an error from process_act() we validate that the input data was generated // randomly to ensure real act generation still produces valid transitions. #[inline] -fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), String> { +fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedError> { let mut test_ctx = TestCtx::make(generator)?; - let mut used_generated_data = false; - // Possibly generate bad data for act1 and ensure that the responder does not panic - let mut act1 = test_ctx.act1; - if generator.generate_bool()? { - act1 = (generator.generate_bytes(50)?).to_vec(); - used_generated_data = true; + // Possibly generate bad data for act1 + let (mut act1, mut used_generated_data) = maybe_generate_bad_act(generator, test_ctx.act1)?; + + // Optionally, add garbage data to the end + used_generated_data |= maybe_add_garbage(generator, &mut act1)?; + + // Split act1 into between 1..7 chunks + let act1_chunks = split_vec(generator, &act1)?; + + let mut act2_option = None; + for partial_act1 in act1_chunks { + match test_ctx.responder_handshake.process_act(&partial_act1) { + // Save valid act2 for initiator + Ok((Some(act2_option_inner), None)) => { + act2_option = Some(act2_option_inner); + }, + // Partial act + Ok((None, None)) => { } + // errors are fine as long as they happened due to using bad data + Err(_) => { + assert!(used_generated_data); + return Ok(()); + } + _ => panic!("responder required to output act bytes and no conduit/pubkey") + }; } + let act2 = act2_option.unwrap(); - let mut act2 = match test_ctx.responder_handshake.process_act(&act1) { - Ok((Some(act2), None)) => { - act2 - } - Err(_) => { - assert!(used_generated_data); - return Err("generated expected failure with bad data".to_string()); - } - _ => panic!("responder required to output act bytes and no conduit/pubkey") - }; + // Possibly generate bad data for act2 + let (mut act2, is_bad_data) = maybe_generate_bad_act(generator, act2)?; - // Possibly generate bad data for act2 and ensure that the initiator does not panic - if generator.generate_bool()? { - act2 = (generator.generate_bytes(50)?).to_vec(); - used_generated_data = true; - } + // Optionally, add garbage data to the end + let did_add_garbage = maybe_add_garbage(generator, &mut act2)?; - let (mut act3, (mut initiator_conduit, responder_pubkey)) = match test_ctx.initiator_handshake.process_act(&act2) { - Ok((Some(act3), Some((conduit, remote_pubkey)))) => { - (act3, (conduit, remote_pubkey)) - } - Err(_) => { - assert!(used_generated_data); - return Err("generated expected failure with bad data".to_string()); - } - _ => panic!("initiator required to output act bytes and no conduit/pubkey") - }; + // Keep track of whether or not we have generated bad data up to this point + used_generated_data |= (is_bad_data | did_add_garbage); - // Possibly generate bad data for act3 and ensure that the responder does not panic - if generator.generate_bool()? { - act3 = (generator.generate_bytes(66)?).to_vec(); - used_generated_data = true; + // Split act2 into between 1..7 chunks + let act2_chunks = split_vec(generator, &act2)?; + + let mut act3_option = None; + let mut conduit_and_remote_pubkey_option = None; + for partial_act2 in act2_chunks { + match test_ctx.initiator_handshake.process_act(&partial_act2) { + Ok((Some(act3), Some(conduit_and_remote_pubkey_option_inner))) => { + act3_option = Some(act3); + conduit_and_remote_pubkey_option = Some(conduit_and_remote_pubkey_option_inner); + + // Valid conduit and pubkey indicates handshake is over + break; + } + // Partial act + Ok((None, None)) => { }, + // errors are fine as long as they happened due to using bad data + Err(_) => { + assert!(used_generated_data); + return Ok(()); + } + _ => panic!("initiator required to output act bytes, conduit, and pubkey") + }; } - let (mut responder_conduit, initiator_pubkey) = match test_ctx.responder_handshake.process_act(&act3) { - Ok((None, Some((conduit, remote_pubkey)))) => { - (conduit, remote_pubkey) - } - Err(_) => { - // extremely unlikely we randomly generate a correct act3, but if so.. reset this - assert!(used_generated_data); - return Err("generated expected failure with bad data".to_string()); - }, - _ => panic!("responder required to output conduit/remote pubkey and no act bytes") - }; + // Ensure we actually received act3 bytes, conduit, and remote pubkey from process_act() + let act3 = act3_option.unwrap(); + let (mut initiator_conduit, responder_pubkey) = conduit_and_remote_pubkey_option.unwrap(); + + // Possibly generate bad data for act3 + let (mut act3, is_bad_data) = maybe_generate_bad_act(generator, act3)?; + + // Optionally, add garbage data to the end + let did_add_garbage = maybe_add_garbage(generator, &mut act3)?; + + // Keep track of whether or not we have generated bad data up to this point + used_generated_data |= (is_bad_data | did_add_garbage); + + // Split act3 into between 1..7 chunks + let act3_chunks = split_vec(generator, &act3)?; + + let mut conduit_and_remote_pubkey_option = None; + for partial_act3 in act3_chunks { + match test_ctx.responder_handshake.process_act(&partial_act3) { + Ok((None, Some(conduit_and_remote_pubkey_option_inner))) => { + conduit_and_remote_pubkey_option = Some(conduit_and_remote_pubkey_option_inner); + + // Valid conduit and pubkey indicates handshake is over + break; + }, + // partial act + Ok((None, None)) => { }, + // errors are fine as long as they happened due to using bad data + Err(_) => { + assert!(used_generated_data); + return Ok(()); + }, + _ => panic!("responder required to output conduit, and pubkey") + }; + } + // Ensure we actually received conduit and remote pubkey from process_act() + let (mut responder_conduit, initiator_pubkey) = conduit_and_remote_pubkey_option.unwrap(); // The handshake should complete with each peer knowing the static_public_key of the remote peer if initiator_pubkey != test_ctx.initiator_static_public_key { @@ -211,9 +314,7 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), String> { } // The nodes should be able to communicate over the conduit - do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit)?; - - unreachable!(); + do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit, used_generated_data) } #[inline] @@ -226,13 +327,19 @@ fn do_test(data: &[u8]) { _ => { return } }; + // The only valid error that can leak here is the FuzzGen error to indicate + // the input bytes have been exhausted and the test can't proceed. Everything + // else should be caught and handled by the individual tests to validate any + // errors. if do_valid_handshake { match do_completed_handshake_test(&mut generator) { - _ => {} + Err(_) => { } + _ => { } } } else { match do_handshake_test(&mut generator) { - _ => {} + Err(_) => { } + _ => { } } } } @@ -253,7 +360,7 @@ mod test { #[test] fn data_generator_empty() { let mut generator = FuzzGen::new(&[]); - assert_eq!(generator.generate_bool().err(), Some("out of bytes".to_string())); + assert_eq!(generator.generate_bool(), Err(GeneratorFinishedError { })); } #[test] @@ -272,13 +379,13 @@ mod test { fn data_generator_bool_then_error() { let mut generator = FuzzGen::new(&[1]); assert!(generator.generate_bool().unwrap()); - assert_eq!(generator.generate_bool().err(), Some("out of bytes".to_string())); + assert_eq!(generator.generate_bool(), Err(GeneratorFinishedError { })); } #[test] fn data_generator_bytes_too_many() { let mut generator = FuzzGen::new(&[1, 2, 3, 4]); - assert_eq!(generator.generate_bytes(5).err(), Some("out of bytes".to_string())); + assert_eq!(generator.generate_bytes(5), Err(GeneratorFinishedError { })); } #[test] @@ -297,6 +404,93 @@ mod test { assert_eq!(result, &input[..2]); let result = generator.generate_bytes(2).unwrap(); assert_eq!(result, &input[2..]); - assert_eq!(generator.generate_bytes(1).err(), Some("out of bytes".to_string())); + assert_eq!(generator.generate_bytes(1), Err(GeneratorFinishedError { })); + } + + #[test] + fn maybe_generate_bad_act_gen_bad() { + // 1 is used to take bad branch and 2 is used to generate bad act + let input = [1, 2]; + let mut generator = FuzzGen::new(&input); + + let original_act = &[5]; + + let (act, is_bad) = maybe_generate_bad_act(&mut generator, original_act.to_vec()).unwrap(); + assert!(is_bad); + assert_eq!(act, &[2]); + } + + #[test] + fn maybe_generate_bad_act_gen_good() { + // 0 is used to take good branch + let input = [0]; + let mut generator = FuzzGen::new(&input); + let original_act = &[5]; + + let (act, is_bad) = maybe_generate_bad_act(&mut generator, original_act.to_vec()).unwrap(); + assert!(!is_bad); + assert_eq!(act, &[5]); + } + + #[test] + fn maybe_add_garbage_did_add() { + // 0x10 consumed to specify amount of garbage (1 byte) and 2 is consumed to add garbage + let input = [0x10, 2]; + let mut generator = FuzzGen::new(&input); + let mut act = vec![5]; + + let did_add_garbage = maybe_add_garbage(&mut generator, &mut act).unwrap(); + assert!(did_add_garbage); + assert_eq!(act, &[5, 2]); + } + + #[test] + fn maybe_add_garbage_no_add() { + // 0x10 consumed to specify amount of garbage (1 byte) and 2 is consumed to add garbage + let input = [0]; + let mut generator = FuzzGen::new(&input); + let mut act = vec![5]; + + let did_add_garbage = maybe_add_garbage(&mut generator, &mut act).unwrap(); + assert!(!did_add_garbage); + assert_eq!(act, &[5]); + } + + #[test] + fn split_vec_1_chunk() { + // 0 consumed for number of chunks (1 is min) + let input = [0]; + let mut generator = FuzzGen::new(&input); + let act = vec![5, 6]; + + let act_parts = split_vec(&mut generator, &act).unwrap(); + assert_eq!(act_parts.len(), 1); + assert_eq!(act_parts[0], &[5, 6]); + } + + #[test] + fn split_vec_2_chunks() { + // 40 consumed for number of chunks. Chunk size is equal to the high three bits (2) + let input = [0x40]; + let mut generator = FuzzGen::new(&input); + let act = vec![5, 6]; + + let act_parts = split_vec(&mut generator, &act).unwrap(); + assert_eq!(act_parts.len(), 2); + assert_eq!(act_parts[0], &[5]); + assert_eq!(act_parts[1], &[6]); + } + #[test] + fn split_vec_2_chunks_odd() { + // 40 consumed for number of chunks. Chunk size is equal to the high three bits (2) + let input = [0x40]; + let mut generator = FuzzGen::new(&input); + let act = vec![5, 6, 7, 8, 9]; + + let act_parts = split_vec(&mut generator, &act).unwrap(); + assert_eq!(act_parts.len(), 3); + assert_eq!(act_parts[0], &[5, 6]); + assert_eq!(act_parts[1], &[7, 8]); + assert_eq!(act_parts[2], &[9]); } } \ No newline at end of file From 4e23b88d5afb93f21d55590e396a20c2a360d2e8 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 24 Aug 2020 17:35:00 -0700 Subject: [PATCH 62/96] review: Split outbound initialization into new()/set_up() To avoid tuple returns from a single initialization function, create a setup_outbound() function that is only callable by the outbound PeerHandshake, but doesn't leak implementation details. --- fuzz/src/peer_crypt.rs | 3 +- lightning/src/ln/peers/handler.rs | 3 +- lightning/src/ln/peers/handshake/mod.rs | 61 +++++++++++++++++++++---- 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index d83857c957e..a9f9d5b7b1c 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -87,7 +87,8 @@ impl TestCtx { let responder_static_public_key = PublicKey::from_secret_key(&curve, &responder_static_private_key); let responder_ephemeral_private_key = generator.generate_secret_key()?; - let (act1, initiator_handshake) = PeerHandshake::create_and_initialize_outbound(&initiator_static_private_key, &responder_static_public_key, &initiator_ephemeral_private_key); + let mut initiator_handshake = PeerHandshake::new_outbound(&initiator_static_private_key, &responder_static_public_key, &initiator_ephemeral_private_key); + let act1 = initiator_handshake.set_up_outbound(); let responder_handshake = PeerHandshake::new_inbound(&responder_static_private_key, &responder_ephemeral_private_key); Ok(TestCtx { diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 9c0b11394a0..9f7b424452c 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -356,7 +356,8 @@ impl PeerManager Result, PeerHandleError> { - let (initial_bytes, handshake) = PeerHandshake::create_and_initialize_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); + let mut handshake = PeerHandshake::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); + let initial_bytes = handshake.set_up_outbound(); let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 3bf47ebb60a..571a912674c 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -13,25 +13,42 @@ mod states; /// Currently requires explicit ephemeral private key specification. pub struct PeerHandshake { state: Option, + ready_for_process: bool } impl PeerHandshake { /// Instantiate a new handshake with a node identity secret key and an ephemeral private key - pub fn create_and_initialize_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> (Vec, Self) { + pub fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { let state = HandshakeState::new_initiator(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key); - // This transition does not have a failure path - let (response_vec_opt, next_state) = state.next(&[]).unwrap(); - (response_vec_opt.unwrap(), Self { state: Some(next_state) }) + Self { + state: Some(state), + ready_for_process: false + } } /// Instantiate a new handshake in anticipation of a peer's first handshake act pub fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { Self { - state: Some(HandshakeState::new_responder(responder_static_private_key, responder_ephemeral_private_key)) + state: Some(HandshakeState::new_responder(responder_static_private_key, responder_ephemeral_private_key)), + ready_for_process: true } } + /// Initializes the outbound handshake and provides the initial bytes to send to the responder + pub fn set_up_outbound(&mut self) -> Vec { + assert!(!self.ready_for_process); + let cur_state = self.state.take().unwrap(); + + // This transition does not have a failure path + let (response_vec_opt, next_state) = cur_state.next(&[]).unwrap(); + + self.state = Some(next_state); + + self.ready_for_process = true; + response_vec_opt.unwrap() + } + /// Process act dynamically /// # Arguments /// `input`: Byte slice received from peer as part of the handshake protocol @@ -41,6 +58,7 @@ impl PeerHandshake { /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Some(Conduit, PublicKey) if the handshake was just processed to completion and messages can now be encrypted and decrypted pub fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + assert!(self.ready_for_process); let cur_state = self.state.take().unwrap(); let (act_opt, mut next_state) = cur_state.next(input)?; @@ -85,7 +103,8 @@ mod test { let inbound_static_public_key = PublicKey::from_secret_key(&curve, &inbound_static_private_key); let inbound_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); - let (act1, outbound_handshake) = PeerHandshake::create_and_initialize_outbound(&outbound_static_private_key, &inbound_static_public_key, &outbound_ephemeral_private_key); + let mut outbound_handshake= PeerHandshake::new_outbound(&outbound_static_private_key, &inbound_static_public_key, &outbound_ephemeral_private_key); + let act1 = outbound_handshake.set_up_outbound(); let inbound_handshake = PeerHandshake::new_inbound(&inbound_static_private_key, &inbound_ephemeral_private_key); TestCtx { @@ -113,9 +132,35 @@ mod test { } } + // Test that the outbound needs to call set_up_outbound() before process_act() + #[test] + #[should_panic(expected = "assertion failed: self.ready_for_process")] + fn new_outbound_no_set_up_panics() { + let curve = secp256k1::Secp256k1::new(); + + let outbound_static_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let outbound_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); + let inbound_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let inbound_static_public_key = PublicKey::from_secret_key(&curve, &inbound_static_private_key); + + let mut outbound_handshake= PeerHandshake::new_outbound(&outbound_static_private_key, &inbound_static_public_key, &outbound_ephemeral_private_key); + outbound_handshake.process_act(&[]).unwrap(); + } + + // Test that calling set_up_outbound() on the inbound panics + #[test] + #[should_panic(expected = "assertion failed: !self.ready_for_process")] + fn new_inbound_calling_set_up_panics() { + let inbound_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let inbound_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); + + let mut inbound_handshake = PeerHandshake::new_inbound(&inbound_static_private_key, &inbound_ephemeral_private_key); + inbound_handshake.set_up_outbound(); + } + // Default Outbound::Uninitiated #[test] - fn peer_handshake_new_outbound() { + fn new_outbound() { let test_ctx = TestCtx::new(); assert_matches!(test_ctx.outbound_handshake.state, Some(HandshakeState::InitiatorAwaitingActTwo(_))); @@ -123,7 +168,7 @@ mod test { // Default Inbound::AwaitingActOne #[test] - fn peer_handshake_new_inbound() { + fn new_inbound() { let test_ctx = TestCtx::new(); assert_matches!(test_ctx.inbound_handshake.state, Some(HandshakeState::ResponderAwaitingActOne(_))); From d7b5f4acb5e8e2355936131c1215f160afa3ef87 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 26 Aug 2020 11:32:42 -0700 Subject: [PATCH 63/96] feature: Tighten the constraints for act message sizes Proper handshake peers won't send more bytes than required for act1 and act2 and it is impossible to generate future acts without first receiving an interleaved response. In those cases, the peer is misbehaving and we can fail early. This unlocks a Vec-less design in the handshake code now that there is an upper limit on read buffer sizes. --- lightning/src/ln/peers/handshake/states.rs | 66 ++++++++++------------ 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 8aba9fe20c1..7eca40f68c8 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -181,6 +181,12 @@ impl IHandshakeState for ResponderAwaitingActOneState { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); + // Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since initiator data + // is required to generate act3 (so it can't come before we transition) + if read_buffer.len() > ACT_ONE_TWO_LENGTH { + return Err("Act One too large".to_string()); + } + // In the event of a partial fill, stay in the same state and wait for more data if read_buffer.len() < ACT_ONE_TWO_LENGTH { return Ok(( @@ -238,6 +244,12 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let mut read_buffer = self.read_buffer; read_buffer.extend_from_slice(input); + // Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since responder data + // is required to generate post-authentication messages (so it can't come before we transition) + if read_buffer.len() > ACT_ONE_TWO_LENGTH { + return Err("Act Two too large".to_string()); + } + // In the event of a partial fill, stay in the same state and wait for more data if read_buffer.len() < ACT_ONE_TWO_LENGTH { return Ok(( @@ -289,7 +301,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { // 7. rn = 0, sn = 0 // - done by Conduit - let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); + let conduit = Conduit::new(sending_key, receiving_key, chaining_key); // Send m = 0 || c || t over the network buffer let mut act_three = Vec::with_capacity(ACT_THREE_LENGTH); @@ -298,14 +310,6 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { act_three.extend(&authentication_tag); assert_eq!(act_three.len(), ACT_THREE_LENGTH); - // Any remaining data in the read buffer would be encrypted, so transfer ownership - // to the Conduit for future use. In this case, it is unlikely that any valid data - // exists, since the responder doesn't have Act3 - if read_buffer.len() > 0 { - conduit.read(&read_buffer[..]); - read_buffer.drain(..); - } - Ok(( Some(act_three), HandshakeState::Complete(Some((conduit, responder_static_public_key))) @@ -600,18 +604,16 @@ mod test { assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_)); } - // Responder::AwaitingActOne -> AwaitingActThree - // TODO: Should this fail since we don't expect data > ACT_ONE_TWO_LENGTH and likely indicates - // a bad peer? + // Responder::AwaitingActOne -> AwaitingActThree (bad peer) + // Act2 requires data from the initiator. If we receive a payload for act1 that is larger than + // expected it indicates a bad peer #[test] fn awaiting_act_one_to_awaiting_act_three_input_extra_bytes() { let test_ctx = TestCtx::new(); let mut act1 = test_ctx.valid_act1; act1.extend_from_slice(&[1]); - let (act2, awaiting_act_three_state) = test_ctx.responder.next(&act1).unwrap(); - assert_eq!(act2.unwrap(), test_ctx.valid_act2); - assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_)); + assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("Act One too large"))); } // Responder::AwaitingActOne -> AwaitingActThree (segmented calls) @@ -658,36 +660,26 @@ mod test { assert_eq!(test_ctx.responder.next(&act1).err(), Some(String::from("invalid hmac"))); } - // Initiator::AwaitingActTwo -> Complete - // RFC test vector: transport-initiator successful handshake + // Initiator::AwaitingActTwo -> Complete (bad peer) + // Initiator data is required to generate post-authentication messages. This means any extra + // data indicates a bad peer. #[test] - fn awaiting_act_two_to_complete() { + fn awaiting_act_two_to_complete_extra_bytes() { let test_ctx = TestCtx::new(); let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &test_ctx.valid_act2); - - let (conduit, remote_pubkey) = if let Complete(Some((conduit, remote_pubkey))) = complete_state { - (conduit, remote_pubkey) - } else { - panic!(); - }; + let mut act2 = test_ctx.valid_act2; + act2.extend_from_slice(&[1]); - assert_eq!(act3, test_ctx.valid_act3); - assert_eq!(remote_pubkey, test_ctx.responder_static_public_key); - assert_eq!(0, conduit.decryptor.read_buffer_length()); + assert_eq!(awaiting_act_two_state.next(&act2).err(), Some(String::from("Act Two too large"))); } - // Initiator::AwaitingActTwo -> Complete (with extra data) - // Ensures that any remaining data in the read buffer is transferred to the conduit once - // the handshake is complete - // TODO: Is this valid? Don't we expect peers to need ActThree before sending additional data? + // Initiator::AwaitingActTwo -> Complete + // RFC test vector: transport-initiator successful handshake #[test] - fn awaiting_act_two_to_complete_excess_bytes_are_in_conduit() { + fn awaiting_act_two_to_complete() { let test_ctx = TestCtx::new(); let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - let mut act2 = test_ctx.valid_act2; - act2.extend_from_slice(&[1; 100]); - let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &act2); + let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &test_ctx.valid_act2); let (conduit, remote_pubkey) = if let Complete(Some((conduit, remote_pubkey))) = complete_state { (conduit, remote_pubkey) @@ -697,7 +689,7 @@ mod test { assert_eq!(act3, test_ctx.valid_act3); assert_eq!(remote_pubkey, test_ctx.responder_static_public_key); - assert_eq!(100, conduit.decryptor.read_buffer_length()); + assert_eq!(0, conduit.decryptor.read_buffer_length()); } // Initiator::AwaitingActTwo -> Complete (segmented calls) From 5f69b6a7377f81188054680c3b1aaffb044b251a Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 25 Aug 2020 17:02:53 -0700 Subject: [PATCH 64/96] perf: Replace Vec w/ static arrays for act buffers After reviewing #494 there was design feedback on the use of Vec vs. arrays in this layer of the code for fragmentation reasons. To get ahead of the same issues in this new state machine and to limit the behavior changes from master, remove Vec from the state machine in favor of thin wrappers around fixed-size arrays. This patch reintroduces the Act object (a thin wrapper around fixed size arrays) with some convenience features to make them a bit easier to pass around and build. The Handshake code is still note Vec-clean as the encryption code uses Vecs during encryption, but it is one step closer to passing back slices to the peer_handler. --- lightning/src/ln/peers/handshake/acts.rs | 171 +++++++++++++++++++++ lightning/src/ln/peers/handshake/mod.rs | 10 +- lightning/src/ln/peers/handshake/states.rs | 117 +++++++------- 3 files changed, 236 insertions(+), 62 deletions(-) create mode 100644 lightning/src/ln/peers/handshake/acts.rs diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs new file mode 100644 index 00000000000..8ce608d147d --- /dev/null +++ b/lightning/src/ln/peers/handshake/acts.rs @@ -0,0 +1,171 @@ +//! Helper library for working with NOISE handshake Act data. Contains utilities for passing Act +//! objects around and building them from received data. +//! Act objects are thin wrappers about raw arrays for stack-based processing as well as convenient +//! coercion to slices for flexible use by the higher-level modules. + +use std::{cmp, ops}; + +pub const ACT_ONE_TWO_LENGTH: usize = 50; +pub const ACT_THREE_LENGTH: usize = 66; +pub const EMPTY_ACT_ONE: ActOne = [0; ACT_ONE_TWO_LENGTH]; +pub const EMPTY_ACT_TWO: ActTwo = EMPTY_ACT_ONE; +pub const EMPTY_ACT_THREE: ActThree = [0; ACT_THREE_LENGTH]; +type ActOne = [u8; ACT_ONE_TWO_LENGTH]; +type ActTwo = ActOne; +type ActThree = [u8; ACT_THREE_LENGTH]; + +/// Wrapper for any act message +pub(super) enum Act { + One(ActOne), + Two(ActTwo), + Three(ActThree) +} + +impl Act { + /// Returns the size of the underlying array + fn len(&self) -> usize { + self.as_ref().len() + } +} + +impl From for Act { + /// Convert a finished ActBuilder into an Act + fn from(act_builder: ActBuilder) -> Self { + assert!(act_builder.is_finished()); + act_builder.partial_act + } +} + +impl ops::Deref for Act { + type Target = [u8]; + + /// Allows automatic coercion to slices in function calls + /// &Act -> &[u8] + fn deref(&self) -> &Self::Target { + match self { + &Act::One(ref act) => { + act + } + &Act::Two(ref act) => { + act + } + &Act::Three(ref act) => { + act + } + } + } +} + +impl AsRef<[u8]> for Act { + /// Allow convenient exposure of the underlying array through as_ref() + /// Act.as_ref() -> &[u8] + fn as_ref(&self) -> &[u8] { + &self + } +} + +// Simple fill implementation for both almost-identical structs to deduplicate code +// $act: Act[One|Two|Three], $input: &[u8]; returns &[u8] of remaining input that was not processed +macro_rules! fill_impl { + ($act:expr, $write_pos:expr, $input:expr) => {{ + let fill_amount = cmp::min($act.len() - $write_pos, $input.len()); + + $act[$write_pos..$write_pos + fill_amount].copy_from_slice(&$input[..fill_amount]); + + $write_pos += fill_amount; + &$input[fill_amount..] + }} +} + +/// Light wrapper around an Act that allows multiple fill() calls before finally +/// converting to an Act via Act::from(act_builder). Handles all of the bookkeeping +/// and edge cases of the array fill +pub(super) struct ActBuilder { + partial_act: Act, + write_pos: usize +} + +impl ActBuilder { + /// Returns a new ActBuilder for Act::One + pub(super) fn new(empty_act: Act) -> Self { + Self { + partial_act: empty_act, + write_pos: 0 + } + } + + /// Fills the Act with bytes from input and returns the unprocessed bytes + pub(super) fn fill<'a>(&mut self, input: &'a [u8]) -> &'a [u8] { + match &mut self.partial_act { + &mut Act::One(ref mut act) => { + fill_impl!(act, self.write_pos, input) + } + &mut Act::Two(ref mut act) => { + fill_impl!(act, self.write_pos, input) + } + &mut Act::Three(ref mut act) => { + fill_impl!(act, self.write_pos, input) + } + } + } + + /// Returns true if the Act is finished building (enough bytes via fill()) + pub(super) fn is_finished(&self) -> bool { + self.write_pos == self.partial_act.len() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + // Test bookkeeping of partial fill + #[test] + fn partial_fill() { + let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); + + let remaining = builder.fill(&[1, 2, 3]); + assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); + assert_eq!(builder.write_pos, 3); + assert!(!builder.is_finished()); + assert_eq!(remaining, &[]); + } + + // Test bookkeeping of exact fill + #[test] + fn exact_fill() { + let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); + + let input = [0; 50]; + let remaining = builder.fill(&input); + assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); + assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH); + assert!(builder.is_finished()); + assert_eq!(Act::from(builder).as_ref(), &input[..]); + assert_eq!(remaining, &[]); + } + + // Test bookkeeping of overfill + #[test] + fn over_fill() { + let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); + + let input = [0; 51]; + let remaining = builder.fill(&input); + + assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); + assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH); + assert!(builder.is_finished()); + assert_eq!(Act::from(builder).as_ref(), &input[..50]); + assert_eq!(remaining, &[0]); + } + + // Converting an unfinished ActBuilder panics + #[test] + #[should_panic(expected="as")] + fn convert_not_finished_panics() { + let builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); + assert_eq!(&Act::from(builder).as_ref(), &[]); + } +} + diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 571a912674c..7443207c137 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -7,6 +7,7 @@ use bitcoin::secp256k1::{PublicKey, SecretKey}; use ln::peers::conduit::Conduit; use ln::peers::handshake::states::{HandshakeState, IHandshakeState}; +mod acts; mod states; /// Object for managing handshakes. @@ -46,7 +47,7 @@ impl PeerHandshake { self.state = Some(next_state); self.ready_for_process = true; - response_vec_opt.unwrap() + response_vec_opt.unwrap().to_vec() } /// Process act dynamically @@ -61,7 +62,12 @@ impl PeerHandshake { assert!(self.ready_for_process); let cur_state = self.state.take().unwrap(); - let (act_opt, mut next_state) = cur_state.next(input)?; + // Convert the Act to a Vec before passing it back. Next patch removes this in favor + // of passing back a slice. + let (act_opt, mut next_state) = match cur_state.next(input)? { + (Some(act), next_state) => (Some(act.to_vec()), next_state), + (None, next_state) => (None, next_state) + }; let result = match next_state { HandshakeState::Complete(ref mut conduit_and_pubkey) => { diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 7eca40f68c8..a2b64928bfc 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -6,9 +6,7 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; - -const ACT_ONE_TWO_LENGTH: usize = 50; -const ACT_THREE_LENGTH: usize = 66; +use ln::peers::handshake::acts::{Act, ActBuilder, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; type ChainingKey = [u8; 32]; @@ -34,7 +32,7 @@ pub(super) enum HandshakeState { // Trait for all individual states to implement that ensure HandshakeState::next() can // delegate to a common function signature. pub(super) trait IHandshakeState { - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String>; + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String>; } // Enum dispatch for state machine. Single public interface can statically dispatch to all states @@ -48,7 +46,7 @@ impl HandshakeState { } impl IHandshakeState for HandshakeState { - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { match self { HandshakeState::InitiatorStarting(state) => { state.next(input) }, HandshakeState::ResponderAwaitingActOne(state) => { state.next(input) }, @@ -77,7 +75,7 @@ pub(super) struct ResponderAwaitingActOneState { responder_ephemeral_public_key: PublicKey, chaining_key: Sha256, hash: Sha256, - read_buffer: Vec + act_one_builder: ActBuilder } // Handshake state of the Initiator prior to receiving Act 2 @@ -88,7 +86,7 @@ pub(super) struct InitiatorAwaitingActTwoState { responder_static_public_key: PublicKey, chaining_key: ChainingKey, hash: Sha256, - read_buffer: Vec + act_two_builder: ActBuilder } // Handshake state of the Responder prior to receiving Act 3 @@ -97,7 +95,7 @@ pub(super) struct ResponderAwaitingActThreeState { responder_ephemeral_private_key: SecretKey, chaining_key: ChainingKey, temporary_key: [u8; 32], - read_buffer: Vec + act_three_builder: ActBuilder } impl InitiatorStartingState { @@ -119,7 +117,7 @@ impl InitiatorStartingState { impl IHandshakeState for InitiatorStartingState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { if input.len() > 0 { return Err("first call for initiator must be empty".to_string()); @@ -134,16 +132,18 @@ impl IHandshakeState for InitiatorStartingState { let hash = self.hash; // serialize act one - let (act_one, hash, chaining_key, _) = calculate_act_message( + let mut act_one = EMPTY_ACT_ONE; + let (hash, chaining_key, _) = calculate_act_message( &initiator_ephemeral_private_key, &initiator_ephemeral_public_key, &responder_static_public_key, chaining_key.into_inner(), hash, + &mut act_one ); Ok(( - Some(act_one.to_vec()), + Some(Act::One(act_one)), HandshakeState::InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState { initiator_static_private_key, initiator_static_public_key, @@ -151,7 +151,7 @@ impl IHandshakeState for InitiatorStartingState { responder_static_public_key, chaining_key, hash, - read_buffer: Vec::new() + act_two_builder: ActBuilder::new(Act::Two(EMPTY_ACT_TWO)) }) )) } @@ -169,7 +169,7 @@ impl ResponderAwaitingActOneState { responder_ephemeral_public_key, chaining_key, hash, - read_buffer: Vec::new() + act_one_builder: ActBuilder::new(Act::One(EMPTY_ACT_ONE)) } } } @@ -177,18 +177,19 @@ impl ResponderAwaitingActOneState { impl IHandshakeState for ResponderAwaitingActOneState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { - let mut read_buffer = self.read_buffer; - read_buffer.extend_from_slice(input); + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { + let mut act_one_builder = self.act_one_builder; + let remaining = act_one_builder.fill(input); // Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since initiator data // is required to generate act3 (so it can't come before we transition) - if read_buffer.len() > ACT_ONE_TWO_LENGTH { + if remaining.len() != 0 { return Err("Act One too large".to_string()); } // In the event of a partial fill, stay in the same state and wait for more data - if read_buffer.len() < ACT_ONE_TWO_LENGTH { + if !act_one_builder.is_finished() { + assert_eq!(remaining.len(), 0); return Ok(( None, HandshakeState::ResponderAwaitingActOne(Self { @@ -197,41 +198,43 @@ impl IHandshakeState for ResponderAwaitingActOneState { responder_ephemeral_public_key: self.responder_ephemeral_public_key, chaining_key: self.chaining_key, hash: self.hash, - read_buffer + act_one_builder }) )); } - let hash = self.hash; let responder_static_private_key = self.responder_static_private_key; let chaining_key = self.chaining_key; let responder_ephemeral_private_key = self.responder_ephemeral_private_key; let responder_ephemeral_public_key = self.responder_ephemeral_public_key; + let act_one = Act::from(act_one_builder); let (initiator_ephemeral_public_key, hash, chaining_key, _) = process_act_message( - &mut read_buffer, + &act_one, &responder_static_private_key, chaining_key.into_inner(), hash, )?; - let (act_two, hash, chaining_key, temporary_key) = calculate_act_message( + let mut act_two = EMPTY_ACT_TWO; + let (hash, chaining_key, temporary_key) = calculate_act_message( &responder_ephemeral_private_key, &responder_ephemeral_public_key, &initiator_ephemeral_public_key, chaining_key, hash, + &mut act_two ); Ok(( - Some(act_two), + Some(Act::Two(act_two)), HandshakeState::ResponderAwaitingActThree(ResponderAwaitingActThreeState { hash, responder_ephemeral_private_key, chaining_key, temporary_key, - read_buffer + act_three_builder: ActBuilder::new(Act::Three(EMPTY_ACT_THREE)) }) )) } @@ -240,18 +243,19 @@ impl IHandshakeState for ResponderAwaitingActOneState { impl IHandshakeState for InitiatorAwaitingActTwoState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (sender) - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { - let mut read_buffer = self.read_buffer; - read_buffer.extend_from_slice(input); + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { + let mut act_two_builder = self.act_two_builder; + let remaining = act_two_builder.fill(input); // Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since responder data // is required to generate post-authentication messages (so it can't come before we transition) - if read_buffer.len() > ACT_ONE_TWO_LENGTH { + if remaining.len() != 0 { return Err("Act Two too large".to_string()); } // In the event of a partial fill, stay in the same state and wait for more data - if read_buffer.len() < ACT_ONE_TWO_LENGTH { + if !act_two_builder.is_finished() { + assert_eq!(remaining.len(), 0); return Ok(( None, HandshakeState::InitiatorAwaitingActTwo(Self { @@ -261,7 +265,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { responder_static_public_key: self.responder_static_public_key, chaining_key: self.chaining_key, hash: self.hash, - read_buffer + act_two_builder }) )); } @@ -272,9 +276,10 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let responder_static_public_key = self.responder_static_public_key; let hash = self.hash; let chaining_key = self.chaining_key; + let act_two = Act::from(act_two_builder); let (responder_ephemeral_public_key, hash, chaining_key, temporary_key) = process_act_message( - &mut read_buffer, + &act_two, &initiator_ephemeral_private_key, chaining_key, hash, @@ -304,14 +309,12 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let conduit = Conduit::new(sending_key, receiving_key, chaining_key); // Send m = 0 || c || t over the network buffer - let mut act_three = Vec::with_capacity(ACT_THREE_LENGTH); - act_three.extend(&[0]); - act_three.extend(&tagged_encrypted_pubkey); - act_three.extend(&authentication_tag); - assert_eq!(act_three.len(), ACT_THREE_LENGTH); + let mut act_three = EMPTY_ACT_THREE; + act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); + act_three[50..].copy_from_slice(&authentication_tag); Ok(( - Some(act_three), + Some(Act::Three(act_three)), HandshakeState::Complete(Some((conduit, responder_static_public_key))) )) } @@ -319,12 +322,13 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { impl IHandshakeState for ResponderAwaitingActThreeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (receiver) - fn next(self, input: &[u8]) -> Result<(Option>, HandshakeState), String> { - let mut read_buffer = self.read_buffer; - read_buffer.extend_from_slice(input); + fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { + let mut act_three_builder = self.act_three_builder; + let remaining = act_three_builder.fill(input); // In the event of a partial fill, stay in the same state and wait for more data - if read_buffer.len() < ACT_THREE_LENGTH { + if !act_three_builder.is_finished() { + assert_eq!(remaining.len(), 0); return Ok(( None, HandshakeState::ResponderAwaitingActThree(Self { @@ -332,7 +336,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { responder_ephemeral_private_key: self.responder_ephemeral_private_key, chaining_key: self.chaining_key, temporary_key: self.temporary_key, - read_buffer + act_three_builder }) )); } @@ -343,7 +347,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { let chaining_key = self.chaining_key; // 1. Read exactly 66 bytes from the network buffer - let act_three_bytes: Vec = read_buffer.drain(..ACT_THREE_LENGTH).collect(); + let act_three_bytes = Act::from(act_three_builder); // 2. Parse the read message (m) into v, c, and t let version = act_three_bytes[0]; @@ -385,10 +389,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // Any remaining data in the read buffer would be encrypted, so transfer ownership // to the Conduit for future use. - if read_buffer.len() > 0 { // have we received more data still? - conduit.read(&read_buffer[..]); - read_buffer.drain(..); - } + conduit.read(remaining); Ok(( None, @@ -417,7 +418,7 @@ fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (S // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) -fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: Sha256) -> (Vec, Sha256, SymmetricKey, SymmetricKey) { +fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: Sha256, act_out: &mut [u8]) -> (Sha256, SymmetricKey, SymmetricKey) { // 1. e = generateKey() (passed in) // 2. h = SHA-256(h || e.pub.serializeCompressed()) let serialized_local_public_key = local_public_ephemeral_key.serialize(); @@ -439,22 +440,18 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e let hash = concat_then_sha256!(hash, tagged_ciphertext); // Send m = 0 || e.pub.serializeCompressed() || c - let mut act = Vec::with_capacity(ACT_ONE_TWO_LENGTH); - act.extend(&[0]); - act.extend_from_slice(&serialized_local_public_key); - act.extend(&tagged_ciphertext); - assert_eq!(act.len(), ACT_ONE_TWO_LENGTH); - (act, hash, chaining_key, temporary_key) + act_out[1..34].copy_from_slice(&serialized_local_public_key); + act_out[34..50].copy_from_slice(&tagged_ciphertext); + + (hash, chaining_key, temporary_key) } // Due to the very high similarity of acts 1 and 2, this method is used to process both // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (receiver) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) -fn process_act_message(read_buffer: &mut Vec, local_private_key: &SecretKey, chaining_key: ChainingKey, hash: Sha256) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), String> { +fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining_key: ChainingKey, hash: Sha256) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), String> { // 1. Read exactly 50 bytes from the network buffer - let act_bytes: Vec = read_buffer.drain(..ACT_ONE_TWO_LENGTH).collect(); - // 2.Parse the read message (m) into v, re, and c let version = act_bytes[0]; let ephemeral_public_key_bytes = &act_bytes[1..34]; @@ -581,7 +578,7 @@ mod test { let test_ctx = TestCtx::new(); let (act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); - assert_eq!(act1, test_ctx.valid_act1); + assert_eq!(act1.as_ref(), test_ctx.valid_act1.as_slice()); assert_matches!(awaiting_act_two_state, InitiatorAwaitingActTwo(_)); } @@ -600,7 +597,7 @@ mod test { let test_ctx = TestCtx::new(); let (act2, awaiting_act_three_state) = test_ctx.responder.next(&test_ctx.valid_act1).unwrap(); - assert_eq!(act2.unwrap(), test_ctx.valid_act2); + assert_eq!(act2.unwrap().as_ref(), test_ctx.valid_act2.as_slice()); assert_matches!(awaiting_act_three_state, ResponderAwaitingActThree(_)); } @@ -687,7 +684,7 @@ mod test { panic!(); }; - assert_eq!(act3, test_ctx.valid_act3); + assert_eq!(act3.as_ref(), test_ctx.valid_act3.as_slice()); assert_eq!(remote_pubkey, test_ctx.responder_static_public_key); assert_eq!(0, conduit.decryptor.read_buffer_length()); } From 28432891dd7bf32a16504e2b602c91b6b6ccf0b6 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 26 Aug 2020 11:12:16 -0700 Subject: [PATCH 65/96] perf: Remove Vec from chacha::encrypt/decrypt In order to limit perf/allocation changes from master, remove the last use of Vec from the handshake code. The decrypt/encrypt code now takes an out parameter to place the decrypted bytes. All handshake users know the fixed-size of the output decryption so they can use arrays. The Conduit code will still allocate a Vec based on the input message and pass it through. After this patch, the handshake code is now Vec-less and copies are minimized. --- lightning/src/ln/peers/chacha.rs | 23 +++++++--------- lightning/src/ln/peers/conduit.rs | 9 +++--- lightning/src/ln/peers/handshake/states.rs | 32 ++++++++++------------ 3 files changed, 29 insertions(+), 35 deletions(-) diff --git a/lightning/src/ln/peers/chacha.rs b/lightning/src/ln/peers/chacha.rs index 4e8d948706f..76742bad452 100644 --- a/lightning/src/ln/peers/chacha.rs +++ b/lightning/src/ln/peers/chacha.rs @@ -3,21 +3,18 @@ use util::chacha20poly1305rfc::ChaCha20Poly1305RFC; pub const TAG_SIZE: usize = 16; -pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8]) -> Vec { +pub fn encrypt(key: &[u8], nonce: u64, associated_data: &[u8], plaintext: &[u8], ciphertext_out: &mut [u8]) { let mut nonce_bytes = [0; 12]; nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce)); let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data); - let mut ciphertext = vec![0u8; plaintext.len()]; let mut authentication_tag = [0u8; 16]; - chacha.encrypt(plaintext, &mut ciphertext, &mut authentication_tag); + chacha.encrypt(plaintext, &mut ciphertext_out[..plaintext.len()], &mut authentication_tag); - let mut tagged_ciphertext = ciphertext; - tagged_ciphertext.extend_from_slice(&authentication_tag); - tagged_ciphertext + ciphertext_out[plaintext.len()..].copy_from_slice(&authentication_tag); } -pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext: &[u8]) -> Result, String> { +pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext: &[u8], plaintext_out: &mut [u8]) -> Result<(), String> { let mut nonce_bytes = [0; 12]; nonce_bytes[4..].copy_from_slice(&byte_utils::le64_to_array(nonce)); @@ -27,14 +24,14 @@ pub fn decrypt(key: &[u8], nonce: u64, associated_data: &[u8], tagged_ciphertext } let end_index = length - 16; let ciphertext = &tagged_ciphertext[0..end_index]; - let authentication_tag = &tagged_ciphertext[end_index..length]; + let authentication_tag = &tagged_ciphertext[end_index..]; let mut chacha = ChaCha20Poly1305RFC::new(key, &nonce_bytes, associated_data); - let mut plaintext = vec![0u8; length - 16]; - let success = chacha.decrypt(ciphertext, &mut plaintext, authentication_tag); - if success { - Ok(plaintext.to_vec()) - } else { + let success = chacha.decrypt(ciphertext, plaintext_out, authentication_tag); + + if !success { Err("invalid hmac".to_string()) + } else { + Ok(()) } } diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index ac2f251e8ee..96f3b9da482 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -119,10 +119,10 @@ impl Encryptor { let mut ciphertext = vec![0u8; TAGGED_MESSAGE_LENGTH_HEADER_SIZE + length as usize + chacha::TAG_SIZE]; - ciphertext[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes)); + chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], &length_bytes, &mut ciphertext[..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]); self.increment_nonce(); - ciphertext[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..].copy_from_slice(&chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer)); + &chacha::encrypt(&self.sending_key, self.sending_nonce as u64, &[0; 0], buffer, &mut ciphertext[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..]); self.increment_nonce(); ciphertext @@ -172,7 +172,7 @@ impl Decryptor { let encrypted_length = &buffer[0..TAGGED_MESSAGE_LENGTH_HEADER_SIZE]; let mut length_bytes = [0u8; MESSAGE_LENGTH_HEADER_SIZE]; - length_bytes.copy_from_slice(&chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length)?); + chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_length, &mut length_bytes)?; self.increment_nonce(); @@ -190,8 +190,9 @@ impl Decryptor { self.pending_message_length = None; let encrypted_message = &buffer[TAGGED_MESSAGE_LENGTH_HEADER_SIZE..message_end_index]; + let mut message = vec![0u8; message_length]; - let message = chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_message)?; + chacha::decrypt(&self.receiving_key, self.receiving_nonce as u64, &[0; 0], encrypted_message, &mut message)?; self.increment_nonce(); diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index a2b64928bfc..6b0a7be63b9 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -285,12 +285,14 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { hash, )?; + let mut act_three = EMPTY_ACT_THREE; + // start serializing act three // 1. c = encryptWithAD(temp_k2, 1, h, s.pub.serializeCompressed()) - let tagged_encrypted_pubkey = chacha::encrypt(&temporary_key, 1, &hash, &initiator_static_public_key.serialize()); + chacha::encrypt(&temporary_key, 1, &hash, &initiator_static_public_key.serialize(), &mut act_three[1..50]); // 2. h = SHA-256(h || c) - let hash = concat_then_sha256!(hash, tagged_encrypted_pubkey); + let hash = concat_then_sha256!(hash, act_three[1..50]); // 3. se = ECDH(s.priv, re) let ecdh = ecdh(&initiator_static_private_key, &responder_ephemeral_public_key); @@ -299,7 +301,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); // 5. t = encryptWithAD(temp_k3, 0, h, zero) - let authentication_tag = chacha::encrypt(&temporary_key, 0, &hash, &[0; 0]); + chacha::encrypt(&temporary_key, 0, &hash, &[0; 0], &mut act_three[50..]); // 6. sk, rk = HKDF(ck, zero) let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); @@ -308,11 +310,6 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { // - done by Conduit let conduit = Conduit::new(sending_key, receiving_key, chaining_key); - // Send m = 0 || c || t over the network buffer - let mut act_three = EMPTY_ACT_THREE; - act_three[1..50].copy_from_slice(&tagged_encrypted_pubkey); - act_three[50..].copy_from_slice(&authentication_tag); - Ok(( Some(Act::Three(act_three)), HandshakeState::Complete(Some((conduit, responder_static_public_key))) @@ -352,7 +349,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // 2. Parse the read message (m) into v, c, and t let version = act_three_bytes[0]; let tagged_encrypted_pubkey = &act_three_bytes[1..50]; - let chacha_tag = &act_three_bytes[50..66]; + let chacha_tag = &act_three_bytes[50..]; // 3. If v is an unrecognized handshake version, then the responder MUST abort the connection attempt. if version != 0 { @@ -361,8 +358,9 @@ impl IHandshakeState for ResponderAwaitingActThreeState { } // 4. rs = decryptWithAD(temp_k2, 1, h, c) - let remote_pubkey_vec = chacha::decrypt(&temporary_key, 1, &hash, &tagged_encrypted_pubkey)?; - let initiator_pubkey = if let Ok(public_key) = PublicKey::from_slice(remote_pubkey_vec.as_slice()) { + let mut remote_pubkey = [0; 33]; + chacha::decrypt(&temporary_key, 1, &hash, &tagged_encrypted_pubkey, &mut remote_pubkey)?; + let initiator_pubkey = if let Ok(public_key) = PublicKey::from_slice(&remote_pubkey) { public_key } else { return Err("invalid remote public key".to_string()); @@ -378,7 +376,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); // 8. p = decryptWithAD(temp_k3, 0, h, t) - let _tag_check = chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag)?; + chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag, &mut [0; 0])?; // 9. rk, sk = HKDF(ck, zero) let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); @@ -434,15 +432,13 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e // 5. ACT1: c = encryptWithAD(temp_k1, 0, h, zero) // 5. ACT2: c = encryptWithAD(temp_k2, 0, h, zero) - let tagged_ciphertext = chacha::encrypt(&temporary_key, 0, &hash, &[0; 0]); + chacha::encrypt(&temporary_key, 0, &hash, &[0; 0], &mut act_out[34..]); // 6. h = SHA-256(h || c) - let hash = concat_then_sha256!(hash, tagged_ciphertext); + let hash = concat_then_sha256!(hash, &act_out[34..]); // Send m = 0 || e.pub.serializeCompressed() || c - act_out[1..34].copy_from_slice(&serialized_local_public_key); - act_out[34..50].copy_from_slice(&tagged_ciphertext); (hash, chaining_key, temporary_key) } @@ -455,7 +451,7 @@ fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining // 2.Parse the read message (m) into v, re, and c let version = act_bytes[0]; let ephemeral_public_key_bytes = &act_bytes[1..34]; - let chacha_tag = &act_bytes[34..50]; + let chacha_tag = &act_bytes[34..]; let ephemeral_public_key = if let Ok(public_key) = PublicKey::from_slice(&ephemeral_public_key_bytes) { public_key @@ -481,7 +477,7 @@ fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); // 7. p = decryptWithAD(temp_k1, 0, h, c) - let _tag_check = chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag)?; + chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag, &mut [0; 0])?; // 8. h = SHA-256(h || c) let hash = concat_then_sha256!(hash, chacha_tag); From 0c528bcd7bfcccb0af35af74dd2aa49c00cd6ac9 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 2 Sep 2020 09:41:15 -0700 Subject: [PATCH 66/96] review: Non-controversial renames, nits, small fixups Clean up small items based on review comments that are expected to be non-controversial so they can all go in one commit. --- lightning/src/ln/peers/handler.rs | 12 ++--- lightning/src/ln/peers/handshake/acts.rs | 55 +++++++++++----------- lightning/src/ln/peers/handshake/mod.rs | 37 +++++++-------- lightning/src/ln/peers/handshake/states.rs | 21 +++++++-- lightning/src/ln/peers/hkdf.rs | 8 ++-- 5 files changed, 71 insertions(+), 62 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 9f7b424452c..69e04af2b9e 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -140,17 +140,17 @@ impl PeerState { }, // Otherwise, handshake may or may not be complete depending on whether or not // we receive a (conduit, pubkey) - Ok((response_vec_opt, conduit_and_remote_pubkey_opt)) => { + Ok((response_vec_option, conduit_and_remote_static_public_key_option)) => { // Any response generated by the handshake sequence is put into the response buffer - if let Some(response_vec) = response_vec_opt { + if let Some(response_vec) = response_vec_option { mutable_response_buffer.push_back(response_vec); } - // if process_act() returns the conduit and remote_pubkey the handshake - // is complete - if let Some((conduit, remote_pubkey)) = conduit_and_remote_pubkey_opt { - (Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(remote_pubkey)) + // if process_act() returns the conduit and remote static public key (node id) + // the handshake is complete + if let Some((conduit, remote_static_public_key)) = conduit_and_remote_static_public_key_option { + (Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(remote_static_public_key)) } else { (None, PeerDataProcessingDecision::Continue) } diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs index 8ce608d147d..c662803b0d5 100644 --- a/lightning/src/ln/peers/handshake/acts.rs +++ b/lightning/src/ln/peers/handshake/acts.rs @@ -5,13 +5,14 @@ use std::{cmp, ops}; -pub const ACT_ONE_TWO_LENGTH: usize = 50; +pub const ACT_ONE_LENGTH: usize = 50; +pub const ACT_TWO_LENGTH: usize = 50; pub const ACT_THREE_LENGTH: usize = 66; -pub const EMPTY_ACT_ONE: ActOne = [0; ACT_ONE_TWO_LENGTH]; -pub const EMPTY_ACT_TWO: ActTwo = EMPTY_ACT_ONE; +pub const EMPTY_ACT_ONE: ActOne = [0; ACT_ONE_LENGTH]; +pub const EMPTY_ACT_TWO: ActTwo = [0; ACT_TWO_LENGTH]; pub const EMPTY_ACT_THREE: ActThree = [0; ACT_THREE_LENGTH]; -type ActOne = [u8; ACT_ONE_TWO_LENGTH]; -type ActTwo = ActOne; +type ActOne = [u8; ACT_ONE_LENGTH]; +type ActTwo = [u8; ACT_TWO_LENGTH]; type ActThree = [u8; ACT_THREE_LENGTH]; /// Wrapper for any act message @@ -64,19 +65,6 @@ impl AsRef<[u8]> for Act { } } -// Simple fill implementation for both almost-identical structs to deduplicate code -// $act: Act[One|Two|Three], $input: &[u8]; returns &[u8] of remaining input that was not processed -macro_rules! fill_impl { - ($act:expr, $write_pos:expr, $input:expr) => {{ - let fill_amount = cmp::min($act.len() - $write_pos, $input.len()); - - $act[$write_pos..$write_pos + fill_amount].copy_from_slice(&$input[..fill_amount]); - - $write_pos += fill_amount; - &$input[fill_amount..] - }} -} - /// Light wrapper around an Act that allows multiple fill() calls before finally /// converting to an Act via Act::from(act_builder). Handles all of the bookkeeping /// and edge cases of the array fill @@ -96,15 +84,28 @@ impl ActBuilder { /// Fills the Act with bytes from input and returns the unprocessed bytes pub(super) fn fill<'a>(&mut self, input: &'a [u8]) -> &'a [u8] { + // Simple fill implementation for both almost-identical structs to deduplicate code + // $act: Act[One|Two|Three], $input: &[u8]; returns &[u8] of remaining input that was not processed + macro_rules! fill_act_content { + ($act:expr, $write_pos:expr, $input:expr) => {{ + let fill_amount = cmp::min($act.len() - $write_pos, $input.len()); + + $act[$write_pos..$write_pos + fill_amount].copy_from_slice(&$input[..fill_amount]); + + $write_pos += fill_amount; + &$input[fill_amount..] + }} + } + match &mut self.partial_act { &mut Act::One(ref mut act) => { - fill_impl!(act, self.write_pos, input) + fill_act_content!(act, self.write_pos, input) } &mut Act::Two(ref mut act) => { - fill_impl!(act, self.write_pos, input) + fill_act_content!(act, self.write_pos, input) } &mut Act::Three(ref mut act) => { - fill_impl!(act, self.write_pos, input) + fill_act_content!(act, self.write_pos, input) } } } @@ -125,7 +126,7 @@ mod tests { let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); let remaining = builder.fill(&[1, 2, 3]); - assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); + assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH); assert_eq!(builder.write_pos, 3); assert!(!builder.is_finished()); assert_eq!(remaining, &[]); @@ -138,8 +139,8 @@ mod tests { let input = [0; 50]; let remaining = builder.fill(&input); - assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); - assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH); + assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH); + assert_eq!(builder.write_pos, ACT_ONE_LENGTH); assert!(builder.is_finished()); assert_eq!(Act::from(builder).as_ref(), &input[..]); assert_eq!(remaining, &[]); @@ -153,8 +154,8 @@ mod tests { let input = [0; 51]; let remaining = builder.fill(&input); - assert_eq!(builder.partial_act.len(), ACT_ONE_TWO_LENGTH); - assert_eq!(builder.write_pos, ACT_ONE_TWO_LENGTH); + assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH); + assert_eq!(builder.write_pos, ACT_ONE_LENGTH); assert!(builder.is_finished()); assert_eq!(Act::from(builder).as_ref(), &input[..50]); assert_eq!(remaining, &[0]); @@ -162,7 +163,7 @@ mod tests { // Converting an unfinished ActBuilder panics #[test] - #[should_panic(expected="as")] + #[should_panic(expected="assertion failed: act_builder.is_finished()")] fn convert_not_finished_panics() { let builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); assert_eq!(&Act::from(builder).as_ref(), &[]); diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 7443207c137..d914b299518 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -14,40 +14,39 @@ mod states; /// Currently requires explicit ephemeral private key specification. pub struct PeerHandshake { state: Option, - ready_for_process: bool + ready_to_process: bool, } impl PeerHandshake { - /// Instantiate a new handshake with a node identity secret key and an ephemeral private key + /// Instantiate a handshake given the peer's static public key. The ephemeral private key MUST + /// generate a new session with strong cryptographic randomness. pub fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { let state = HandshakeState::new_initiator(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key); Self { state: Some(state), - ready_for_process: false + ready_to_process: false, } } - /// Instantiate a new handshake in anticipation of a peer's first handshake act + /// Instantiate a handshake in anticipation of a peer's first handshake act pub fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { Self { state: Some(HandshakeState::new_responder(responder_static_private_key, responder_ephemeral_private_key)), - ready_for_process: true + ready_to_process: true, } } /// Initializes the outbound handshake and provides the initial bytes to send to the responder pub fn set_up_outbound(&mut self) -> Vec { - assert!(!self.ready_for_process); - let cur_state = self.state.take().unwrap(); + assert!(!self.ready_to_process); + self.ready_to_process = true; // This transition does not have a failure path - let (response_vec_opt, next_state) = cur_state.next(&[]).unwrap(); - - self.state = Some(next_state); + let (response_vec_option, conduit_and_remote_static_public_key_option) = self.process_act(&[]).unwrap(); + assert!(conduit_and_remote_static_public_key_option.is_none()); - self.ready_for_process = true; - response_vec_opt.unwrap().to_vec() + response_vec_option.unwrap() } /// Process act dynamically @@ -59,21 +58,19 @@ impl PeerHandshake { /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Some(Conduit, PublicKey) if the handshake was just processed to completion and messages can now be encrypted and decrypted pub fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { - assert!(self.ready_for_process); + assert!(self.ready_to_process); let cur_state = self.state.take().unwrap(); - // Convert the Act to a Vec before passing it back. Next patch removes this in favor - // of passing back a slice. - let (act_opt, mut next_state) = match cur_state.next(input)? { + let (act_option, mut next_state) = match cur_state.next(input)? { (Some(act), next_state) => (Some(act.to_vec()), next_state), (None, next_state) => (None, next_state) }; let result = match next_state { HandshakeState::Complete(ref mut conduit_and_pubkey) => { - Ok((act_opt, conduit_and_pubkey.take())) + Ok((act_option, conduit_and_pubkey.take())) }, - _ => { Ok((act_opt, None)) } + _ => { Ok((act_option, None)) } }; self.state = Some(next_state); @@ -140,7 +137,7 @@ mod test { // Test that the outbound needs to call set_up_outbound() before process_act() #[test] - #[should_panic(expected = "assertion failed: self.ready_for_process")] + #[should_panic(expected = "assertion failed: self.ready_to_process")] fn new_outbound_no_set_up_panics() { let curve = secp256k1::Secp256k1::new(); @@ -155,7 +152,7 @@ mod test { // Test that calling set_up_outbound() on the inbound panics #[test] - #[should_panic(expected = "assertion failed: !self.ready_for_process")] + #[should_panic(expected = "assertion failed: !self.ready_to_process")] fn new_inbound_calling_set_up_panics() { let inbound_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); let inbound_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 6b0a7be63b9..47383f70a07 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -6,8 +6,9 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::{chacha, hkdf}; use ln::peers::conduit::{Conduit, SymmetricKey}; -use ln::peers::handshake::acts::{Act, ActBuilder, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; +use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; +// Alias type to help differentiate between temporary key and chaining key when passing bytes around type ChainingKey = [u8; 32]; // Generate a SHA-256 hash from one or more elements concatenated together @@ -30,7 +31,8 @@ pub(super) enum HandshakeState { } // Trait for all individual states to implement that ensure HandshakeState::next() can -// delegate to a common function signature. +// delegate to a common function signature. May transition to the same state in the event there are +// not yet enough bytes to move forward with the handshake. pub(super) trait IHandshakeState { fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String>; } @@ -181,7 +183,7 @@ impl IHandshakeState for ResponderAwaitingActOneState { let mut act_one_builder = self.act_one_builder; let remaining = act_one_builder.fill(input); - // Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since initiator data + // Any payload larger than ACT_ONE_LENGTH indicates a bad peer since initiator data // is required to generate act3 (so it can't come before we transition) if remaining.len() != 0 { return Err("Act One too large".to_string()); @@ -247,7 +249,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let mut act_two_builder = self.act_two_builder; let remaining = act_two_builder.fill(input); - // Any payload larger than ACT_ONE_TWO_LENGTH indicates a bad peer since responder data + // Any payload larger than ACT_TWO_LENGTH indicates a bad peer since responder data // is required to generate post-authentication messages (so it can't come before we transition) if remaining.len() != 0 { return Err("Act Two too large".to_string()); @@ -310,6 +312,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { // - done by Conduit let conduit = Conduit::new(sending_key, receiving_key, chaining_key); + // 8. Send m = 0 || c || t Ok(( Some(Act::Three(act_three)), HandshakeState::Complete(Some((conduit, responder_static_public_key))) @@ -345,6 +348,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // 1. Read exactly 66 bytes from the network buffer let act_three_bytes = Act::from(act_three_builder); + assert_eq!(act_three_bytes.len(), ACT_THREE_LENGTH); // 2. Parse the read message (m) into v, c, and t let version = act_three_bytes[0]; @@ -414,6 +418,7 @@ fn handshake_state_initialization(responder_static_public_key: &PublicKey) -> (S (hash, chaining_key) } +// Due to the very high similarity of acts 1 and 2, this method is used to process both // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-one (sender) // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_ephemeral_key: &PublicKey, remote_public_key: &PublicKey, chaining_key: ChainingKey, hash: Sha256, act_out: &mut [u8]) -> (Sha256, SymmetricKey, SymmetricKey) { @@ -448,6 +453,11 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (receiver) fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining_key: ChainingKey, hash: Sha256) -> Result<(PublicKey, Sha256, SymmetricKey, SymmetricKey), String> { // 1. Read exactly 50 bytes from the network buffer + // Partial act messages are handled by the callers. By the time it gets here, it + // must be the correct size. + assert_eq!(act_bytes.len(), ACT_ONE_LENGTH); + assert_eq!(act_bytes.len(), ACT_TWO_LENGTH); + // 2.Parse the read message (m) into v, re, and c let version = act_bytes[0]; let ephemeral_public_key_bytes = &act_bytes[1..34]; @@ -476,7 +486,8 @@ fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining // 6. Act2: ck, temp_k2 = HKDF(ck, ee) let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); - // 7. p = decryptWithAD(temp_k1, 0, h, c) + // 7. Act1: p = decryptWithAD(temp_k1, 0, h, c) + // 7. Act2: p = decryptWithAD(temp_k2, 0, h, c) chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag, &mut [0; 0])?; // 8. h = SHA-256(h || c) diff --git a/lightning/src/ln/peers/hkdf.rs b/lightning/src/ln/peers/hkdf.rs index 6ac1391666d..61f6c49f92a 100644 --- a/lightning/src/ln/peers/hkdf.rs +++ b/lightning/src/ln/peers/hkdf.rs @@ -3,7 +3,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; // Allows 1 or more inputs and "concatenates" them together using the input() function // of HmacEngine:: -macro_rules! hmac_hash { +macro_rules! hmac_sha256 { ( $salt:expr, ($( $input:expr ),+ )) => {{ let mut engine = HmacEngine::::new($salt); $( @@ -31,7 +31,7 @@ pub(super) fn derive(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) { // 2.2. Step 1: Extract // HKDF-Extract(salt, IKM) -> PRK // PRK = HMAC-Hash(salt, IKM) - let prk = hmac_hash!(salt, (ikm)); + let prk = hmac_sha256!(salt, (ikm)); // 2.3. Step 2: Expand // HKDF-Expand(PRK, info, L) -> OKM @@ -42,9 +42,9 @@ pub(super) fn derive(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) { // where: // T(0) = empty string (zero length) // T(1) = HMAC-Hash(PRK, T(0) | info | 0x01) - let t1 = hmac_hash!(&prk, (&[1])); + let t1 = hmac_sha256!(&prk, (&[1])); // T(2) = HMAC-Hash(PRK, T(1) | info | 0x02) - let t2 = hmac_hash!(&prk, (&t1, &[2])); + let t2 = hmac_sha256!(&prk, (&t1, &[2])); return (t1, t2) } From 1481fe96ef1bb9dc2d27d20305ad238c8bbd212d Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 2 Sep 2020 09:51:54 -0700 Subject: [PATCH 67/96] review: rename hkdf -> hkdf5869rfc.rs Follow existing pattern used in util/ for consistency. --- lightning/src/ln/peers/conduit.rs | 4 ++-- lightning/src/ln/peers/handshake/states.rs | 14 +++++++------- lightning/src/ln/peers/{hkdf.rs => hkdf5869rfc.rs} | 2 +- lightning/src/ln/peers/mod.rs | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) rename lightning/src/ln/peers/{hkdf.rs => hkdf5869rfc.rs} (98%) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 96f3b9da482..ed0b3bd595a 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -1,6 +1,6 @@ //! Handles all over the wire message encryption and decryption upon handshake completion. -use ln::peers::{chacha, hkdf}; +use ln::peers::{chacha, hkdf5869rfc}; use util::byte_utils; pub(super) type SymmetricKey = [u8; 32]; @@ -106,7 +106,7 @@ impl Conduit { } fn rotate_key(chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { - let (new_chaining_key, new_key) = hkdf::derive(chaining_key, key); + let (new_chaining_key, new_key) = hkdf5869rfc::derive(chaining_key, key); chaining_key.copy_from_slice(&new_chaining_key); key.copy_from_slice(&new_key); } diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 47383f70a07..e37c35e1b1c 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -4,7 +4,7 @@ use bitcoin::hashes::{Hash, HashEngine}; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; -use ln::peers::{chacha, hkdf}; +use ln::peers::{chacha, hkdf5869rfc}; use ln::peers::conduit::{Conduit, SymmetricKey}; use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; @@ -300,13 +300,13 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let ecdh = ecdh(&initiator_static_private_key, &responder_ephemeral_public_key); // 4. ck, temp_k3 = HKDF(ck, se) - let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let (chaining_key, temporary_key) = hkdf5869rfc::derive(&chaining_key, &ecdh); // 5. t = encryptWithAD(temp_k3, 0, h, zero) chacha::encrypt(&temporary_key, 0, &hash, &[0; 0], &mut act_three[50..]); // 6. sk, rk = HKDF(ck, zero) - let (sending_key, receiving_key) = hkdf::derive(&chaining_key, &[0; 0]); + let (sending_key, receiving_key) = hkdf5869rfc::derive(&chaining_key, &[0; 0]); // 7. rn = 0, sn = 0 // - done by Conduit @@ -377,13 +377,13 @@ impl IHandshakeState for ResponderAwaitingActThreeState { let ecdh = ecdh(&responder_ephemeral_private_key, &initiator_pubkey); // 7. ck, temp_k3 = HKDF(ck, se) - let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let (chaining_key, temporary_key) = hkdf5869rfc::derive(&chaining_key, &ecdh); // 8. p = decryptWithAD(temp_k3, 0, h, t) chacha::decrypt(&temporary_key, 0, &hash, &chacha_tag, &mut [0; 0])?; // 9. rk, sk = HKDF(ck, zero) - let (receiving_key, sending_key) = hkdf::derive(&chaining_key, &[0; 0]); + let (receiving_key, sending_key) = hkdf5869rfc::derive(&chaining_key, &[0; 0]); // 10. rn = 0, sn = 0 // - done by Conduit @@ -433,7 +433,7 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e // 4. ACT1: ck, temp_k1 = HKDF(ck, es) // 4. ACT2: ck, temp_k2 = HKDF(ck, ee) - let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let (chaining_key, temporary_key) = hkdf5869rfc::derive(&chaining_key, &ecdh); // 5. ACT1: c = encryptWithAD(temp_k1, 0, h, zero) // 5. ACT2: c = encryptWithAD(temp_k2, 0, h, zero) @@ -484,7 +484,7 @@ fn process_act_message(act_bytes: &[u8], local_private_key: &SecretKey, chaining // 6. Act1: ck, temp_k1 = HKDF(ck, es) // 6. Act2: ck, temp_k2 = HKDF(ck, ee) - let (chaining_key, temporary_key) = hkdf::derive(&chaining_key, &ecdh); + let (chaining_key, temporary_key) = hkdf5869rfc::derive(&chaining_key, &ecdh); // 7. Act1: p = decryptWithAD(temp_k1, 0, h, c) // 7. Act2: p = decryptWithAD(temp_k2, 0, h, c) diff --git a/lightning/src/ln/peers/hkdf.rs b/lightning/src/ln/peers/hkdf5869rfc.rs similarity index 98% rename from lightning/src/ln/peers/hkdf.rs rename to lightning/src/ln/peers/hkdf5869rfc.rs index 61f6c49f92a..546e64e6fc7 100644 --- a/lightning/src/ln/peers/hkdf.rs +++ b/lightning/src/ln/peers/hkdf5869rfc.rs @@ -53,7 +53,7 @@ pub(super) fn derive(salt: &[u8], ikm: &[u8]) -> ([u8; 32], [u8; 32]) { #[cfg(test)] mod test { use hex; - use ln::peers::hkdf::derive; + use ln::peers::hkdf5869rfc::derive; // Test with SHA-256 and zero-length salt/info // Our implementation uses a zero-length info field and returns the first 64 octets. As a result, diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index 072950c0dba..aadef42d67d 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -5,7 +5,7 @@ mod chacha; pub mod handler; -mod hkdf; +mod hkdf5869rfc; #[cfg(feature = "fuzztarget")] pub mod conduit; From 206c219febaf883c35da21041408192bee5cfa57 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 2 Sep 2020 09:55:35 -0700 Subject: [PATCH 68/96] review: Explicitly set version in Act creation Don't rely on the initialized buffer filled with zeros. --- lightning/src/ln/peers/handshake/states.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index e37c35e1b1c..22aee261367 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -313,6 +313,7 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let conduit = Conduit::new(sending_key, receiving_key, chaining_key); // 8. Send m = 0 || c || t + act_three[0] = 0; Ok(( Some(Act::Three(act_three)), HandshakeState::Complete(Some((conduit, responder_static_public_key))) @@ -443,6 +444,7 @@ fn calculate_act_message(local_private_ephemeral_key: &SecretKey, local_public_e let hash = concat_then_sha256!(hash, &act_out[34..]); // Send m = 0 || e.pub.serializeCompressed() || c + act_out[0] = 0; act_out[1..34].copy_from_slice(&serialized_local_public_key); (hash, chaining_key, temporary_key) From 080f5e39c828590e84444b10589180f52f303935 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 2 Sep 2020 10:08:46 -0700 Subject: [PATCH 69/96] review: ActBuilder::fill() returns the number of bytes consumed Instead of returning a subslice of input for the caller to process, just return the number of bytes consume and let them do the accounting. --- lightning/src/ln/peers/handshake/acts.rs | 23 +++++++++++---------- lightning/src/ln/peers/handshake/states.rs | 24 +++++++++++----------- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/peers/handshake/acts.rs b/lightning/src/ln/peers/handshake/acts.rs index c662803b0d5..b24a21c9ddf 100644 --- a/lightning/src/ln/peers/handshake/acts.rs +++ b/lightning/src/ln/peers/handshake/acts.rs @@ -83,7 +83,7 @@ impl ActBuilder { } /// Fills the Act with bytes from input and returns the unprocessed bytes - pub(super) fn fill<'a>(&mut self, input: &'a [u8]) -> &'a [u8] { + pub(super) fn fill(&mut self, input: &[u8]) -> usize { // Simple fill implementation for both almost-identical structs to deduplicate code // $act: Act[One|Two|Three], $input: &[u8]; returns &[u8] of remaining input that was not processed macro_rules! fill_act_content { @@ -93,7 +93,7 @@ impl ActBuilder { $act[$write_pos..$write_pos + fill_amount].copy_from_slice(&$input[..fill_amount]); $write_pos += fill_amount; - &$input[fill_amount..] + fill_amount }} } @@ -125,11 +125,12 @@ mod tests { fn partial_fill() { let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); - let remaining = builder.fill(&[1, 2, 3]); + let input = [1, 2, 3]; + let bytes_read = builder.fill(&input); assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH); assert_eq!(builder.write_pos, 3); assert!(!builder.is_finished()); - assert_eq!(remaining, &[]); + assert_eq!(bytes_read, input.len()); } // Test bookkeeping of exact fill @@ -137,13 +138,13 @@ mod tests { fn exact_fill() { let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); - let input = [0; 50]; - let remaining = builder.fill(&input); + let input = [0; ACT_ONE_LENGTH]; + let bytes_read = builder.fill(&input); assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH); assert_eq!(builder.write_pos, ACT_ONE_LENGTH); assert!(builder.is_finished()); assert_eq!(Act::from(builder).as_ref(), &input[..]); - assert_eq!(remaining, &[]); + assert_eq!(bytes_read, input.len()); } // Test bookkeeping of overfill @@ -151,14 +152,14 @@ mod tests { fn over_fill() { let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE)); - let input = [0; 51]; - let remaining = builder.fill(&input); + let input = [0; ACT_ONE_LENGTH + 1]; + let bytes_read = builder.fill(&input); assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH); assert_eq!(builder.write_pos, ACT_ONE_LENGTH); assert!(builder.is_finished()); - assert_eq!(Act::from(builder).as_ref(), &input[..50]); - assert_eq!(remaining, &[0]); + assert_eq!(Act::from(builder).as_ref(), &input[..ACT_ONE_LENGTH]); + assert_eq!(bytes_read, ACT_ONE_LENGTH); } // Converting an unfinished ActBuilder panics diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 22aee261367..b116349defc 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -181,17 +181,17 @@ impl IHandshakeState for ResponderAwaitingActOneState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-two (sender) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { let mut act_one_builder = self.act_one_builder; - let remaining = act_one_builder.fill(input); + let bytes_read = act_one_builder.fill(input); - // Any payload larger than ACT_ONE_LENGTH indicates a bad peer since initiator data - // is required to generate act3 (so it can't come before we transition) - if remaining.len() != 0 { + // Any payload that is not fully consumed by the builder indicates a bad peer since responder + // data is required to generate act3 (so it can't come before we transition) + if bytes_read < input.len() { return Err("Act One too large".to_string()); } // In the event of a partial fill, stay in the same state and wait for more data if !act_one_builder.is_finished() { - assert_eq!(remaining.len(), 0); + assert_eq!(bytes_read, input.len()); return Ok(( None, HandshakeState::ResponderAwaitingActOne(Self { @@ -247,17 +247,17 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (sender) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { let mut act_two_builder = self.act_two_builder; - let remaining = act_two_builder.fill(input); + let bytes_read = act_two_builder.fill(input); - // Any payload larger than ACT_TWO_LENGTH indicates a bad peer since responder data + // Any payload that is not fully consumed by the builder indicates a bad peer since responder data // is required to generate post-authentication messages (so it can't come before we transition) - if remaining.len() != 0 { + if bytes_read < input.len() { return Err("Act Two too large".to_string()); } // In the event of a partial fill, stay in the same state and wait for more data if !act_two_builder.is_finished() { - assert_eq!(remaining.len(), 0); + assert_eq!(bytes_read, input.len()); return Ok(( None, HandshakeState::InitiatorAwaitingActTwo(Self { @@ -325,11 +325,11 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#act-three (receiver) fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String> { let mut act_three_builder = self.act_three_builder; - let remaining = act_three_builder.fill(input); + let bytes_read = act_three_builder.fill(input); // In the event of a partial fill, stay in the same state and wait for more data if !act_three_builder.is_finished() { - assert_eq!(remaining.len(), 0); + assert_eq!(bytes_read, input.len()); return Ok(( None, HandshakeState::ResponderAwaitingActThree(Self { @@ -392,7 +392,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // Any remaining data in the read buffer would be encrypted, so transfer ownership // to the Conduit for future use. - conduit.read(remaining); + conduit.read(&input[bytes_read..]); Ok(( None, From ed77a474147cfba7d895d98013e92deaaab36810 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 1 Sep 2020 11:16:51 -0700 Subject: [PATCH 70/96] refactor: Abstract SocketDescriptor writing queue To enable better testing, put the code to enqueue data and flush it to a SocketDescriptor behind an object. This patch starts to implement traits for the various separate interface that each object needs. The idea is the consumer of an interface defines it and the dependency objects implement it. This will be useful when creating test doubles for unit tests and helps make the dependencies of each function more clear. Additional uses of trait-based contracts will be more clear in the next patches that start to add more testing. --- lightning/src/ln/peers/handler.rs | 117 +++++--- lightning/src/ln/peers/mod.rs | 1 + lightning/src/ln/peers/outbound_queue.rs | 350 +++++++++++++++++++++++ 3 files changed, 432 insertions(+), 36 deletions(-) create mode 100644 lightning/src/ln/peers/outbound_queue.rs diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 69e04af2b9e..6bc92f4bb36 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -20,7 +20,7 @@ use util::events::{MessageSendEvent, MessageSendEventsProvider}; use util::logger::Logger; use routing::network_graph::NetGraphMsgHandler; -use std::collections::{HashMap,hash_map,HashSet,LinkedList}; +use std::collections::{HashMap,hash_map,HashSet}; use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{cmp,error,hash,fmt}; @@ -31,6 +31,9 @@ use bitcoin::hashes::sha256::HashEngine as Sha256Engine; use bitcoin::hashes::{HashEngine, Hash}; use ln::peers::handshake::PeerHandshake; use ln::peers::conduit::Conduit; +use ln::peers::outbound_queue::OutboundQueue; + +const MSG_BUFF_SIZE: usize = 10; /// Provides references to trait impls which handle different types of messages. pub struct MessageHandler where @@ -111,6 +114,64 @@ enum InitSyncTracker{ NodesSyncing(PublicKey), } +/// Trait representing a container that allows enqueuing of Vec<[u8]> +pub(super) trait PayloadQueuer { + /// Enqueue item to the queue + fn push_back(&mut self, item: Vec); + + /// Returns true if the queue is empty + fn is_empty(&self) -> bool; + + /// Returns the amount of available space in queue + fn queue_space(&self) -> usize; +} + +/// Implement &mut PayloadQueuer passthroughs +impl<'a, T> PayloadQueuer for &'a mut T where + T: PayloadQueuer { + fn push_back(&mut self, item: Vec) { + T::push_back(self, item) + } + + fn is_empty(&self) -> bool { + T::is_empty(self) + } + + fn queue_space(&self) -> usize { + T::queue_space(self) + } +} + +/// Trait representing a container that can try to flush data through a SocketDescriptor +pub(super) trait SocketDescriptorFlusher { + /// Write previously enqueued data to the SocketDescriptor. A return of false indicates the + /// underlying SocketDescriptor could not fulfill the send_data() call and the blocked state + /// has been set. Use unblock() when the SocketDescriptor may have more room. + fn try_flush_one(&mut self, descriptor: &mut impl SocketDescriptor) -> bool; + + /// Clear the blocked state caused when a previous write failed + fn unblock(&mut self); + + /// Check if the container is in a blocked state + fn is_blocked(&self) -> bool; +} + +/// Implement &mut Flushable passthroughs +impl<'a, T> SocketDescriptorFlusher for &'a mut T where + T: SocketDescriptorFlusher { + fn try_flush_one(&mut self, descriptor: &mut impl SocketDescriptor) -> bool { + T::try_flush_one(self, descriptor) + } + + fn unblock(&mut self) { + T::unblock(self) + } + + fn is_blocked(&self) -> bool { + T::is_blocked(self) + } +} + enum PeerState { Authenticating(PeerHandshake), Connected(Conduit), @@ -130,7 +191,7 @@ impl PeerState { } } - fn process_peer_data(&mut self, data: &[u8], mutable_response_buffer: &mut LinkedList>) -> PeerDataProcessingDecision { + fn process_peer_data(&mut self, data: &[u8], pending_outbound_buffer: &mut impl PayloadQueuer) -> PeerDataProcessingDecision { let (new_state_opt, decision) = match self { &mut PeerState::Authenticating(ref mut handshake) => { match handshake.process_act(data) { @@ -144,7 +205,7 @@ impl PeerState { // Any response generated by the handshake sequence is put into the response buffer if let Some(response_vec) = response_vec_option { - mutable_response_buffer.push_back(response_vec); + pending_outbound_buffer.push_back(response_vec); } // if process_act() returns the conduit and remote static public key (node id) @@ -177,9 +238,7 @@ struct Peer { their_node_id: Option, their_features: Option, - pending_outbound_buffer: LinkedList>, - pending_outbound_buffer_first_msg_offset: usize, - awaiting_write_event: bool, + pending_outbound_buffer: OutboundQueue, sync_status: InitSyncTracker, @@ -366,9 +425,7 @@ impl PeerManager PeerManager PeerManager 0 { match peer.sync_status { InitSyncTracker::NoSyncRequested => {}, InitSyncTracker::ChannelsSyncing(c) if c < 0xffff_ffff_ffff_ffff => { - let steps = ((MSG_BUFF_SIZE - peer.pending_outbound_buffer.len() + 2) / 3) as u8; + let steps = ((queue_space + 2) / 3) as u8; let all_messages = self.message_handler.route_handler.get_next_channel_announcements(c, steps); for &(ref announce, ref update_a_option, ref update_b_option) in all_messages.iter() { encode_and_send_msg!(announce); @@ -446,7 +502,7 @@ impl PeerManager { - let steps = (MSG_BUFF_SIZE - peer.pending_outbound_buffer.len()) as u8; + let steps = queue_space as u8; let all_messages = self.message_handler.route_handler.get_next_node_announcements(None, steps); for msg in all_messages.iter() { encode_and_send_msg!(msg); @@ -458,7 +514,7 @@ impl PeerManager unreachable!(), InitSyncTracker::NodesSyncing(key) => { - let steps = (MSG_BUFF_SIZE - peer.pending_outbound_buffer.len()) as u8; + let steps = queue_space as u8; let all_messages = self.message_handler.route_handler.get_next_node_announcements(Some(&key), steps); for msg in all_messages.iter() { encode_and_send_msg!(msg); @@ -471,23 +527,12 @@ impl PeerManager return, - Some(buff) => buff, - }; - - let should_be_reading = peer.pending_outbound_buffer.len() < MSG_BUFF_SIZE; - let pending = &next_buff[peer.pending_outbound_buffer_first_msg_offset..]; - let data_sent = descriptor.send_data(pending, should_be_reading); - peer.pending_outbound_buffer_first_msg_offset += data_sent; - if peer.pending_outbound_buffer_first_msg_offset == next_buff.len() { true } else { false } - } { - peer.pending_outbound_buffer_first_msg_offset = 0; - peer.pending_outbound_buffer.pop_front(); - } else { - peer.awaiting_write_event = true; + // No messages to send + if peer.pending_outbound_buffer.is_empty() { + break; } + + peer.pending_outbound_buffer.try_flush_one(descriptor); } } @@ -506,7 +551,7 @@ impl PeerManager panic!("Descriptor for write_event is not already known to PeerManager"), Some(peer) => { - peer.awaiting_write_event = false; + peer.pending_outbound_buffer.unblock(); self.do_attempt_write_data(descriptor, peer); } }; @@ -684,7 +729,7 @@ impl PeerManager 10 // pause_read + peer.pending_outbound_buffer.queue_space() == 0 // pause_read } }; diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index aadef42d67d..9de3fcb072b 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -6,6 +6,7 @@ mod chacha; pub mod handler; mod hkdf5869rfc; +mod outbound_queue; #[cfg(feature = "fuzztarget")] pub mod conduit; diff --git a/lightning/src/ln/peers/outbound_queue.rs b/lightning/src/ln/peers/outbound_queue.rs new file mode 100644 index 00000000000..5214ba21234 --- /dev/null +++ b/lightning/src/ln/peers/outbound_queue.rs @@ -0,0 +1,350 @@ +/// Abstracts the buffer used to write data through a SocketDescriptor handling partial writes and +/// flow control. + +use ln::peers::handler::{SocketDescriptor, PayloadQueuer, SocketDescriptorFlusher}; +use std::collections::LinkedList; +use std::cmp; + +pub(super) struct OutboundQueue { + blocked: bool, + soft_limit: usize, + buffer: LinkedList>, + buffer_first_msg_offset: usize, +} + +impl PayloadQueuer for OutboundQueue { + /// Unconditionally queue item. May increase queue above soft limit. + fn push_back(&mut self, item: Vec) { + self.buffer.push_back(item); + } + + /// Returns true if the queue is empty + fn is_empty(&self) -> bool { + self.buffer.is_empty() + } + + /// Returns the amount of free space in the queue before the soft limit + fn queue_space(&self) -> usize { + self.soft_limit - cmp::min(self.soft_limit, self.buffer.len()) + } +} +impl SocketDescriptorFlusher for OutboundQueue { + fn try_flush_one(&mut self, descriptor: &mut impl SocketDescriptor) -> bool { + // Exit early if a previous full write failed and haven't heard that there may be more + // room available + if self.blocked { + return false; + } + + let full_write_succeeded = match self.buffer.front() { + None => true, + Some(next_buff) => { + let should_be_reading = self.buffer.len() < self.soft_limit; + let pending = &next_buff[self.buffer_first_msg_offset..]; + let data_sent = descriptor.send_data(pending, should_be_reading); + self.buffer_first_msg_offset += data_sent; + self.buffer_first_msg_offset == next_buff.len() + } + }; + + if full_write_succeeded { + self.buffer_first_msg_offset = 0; + self.buffer.pop_front(); + } else { + self.blocked = true; + } + + full_write_succeeded + } + + fn unblock(&mut self) { + self.blocked = false; + } + + fn is_blocked(&self) -> bool { + self.blocked + } +} + +impl OutboundQueue { + + /// Create a new writer with a soft limit that is used to notify the SocketDescriptor when + /// it is OK to resume reading if it was paused + pub(super) fn new(soft_limit: usize) -> Self { + Self { + blocked: false, + soft_limit, + buffer: LinkedList::new(), + buffer_first_msg_offset: 0, + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::rc::Rc; + use std::cell::RefCell; + use std::hash::Hash; + use std::cmp; + + /// Mock implementation of the SocketDescriptor trait that can be used in tests to finely control + /// the send_data() behavior. + /// + ///Additionally, records the actual calls to send_data() for later validation. + #[derive(Debug, Eq)] + struct SocketDescriptorMock { + /// If true, all send_data() calls will succeed + unbounded: Rc>, + + /// Amount of free space in the descriptor for send_data() bytes + free_space: Rc>, + + /// Vector of arguments and return values to send_data() used for validation + send_recording: Rc, bool)>>>, + } + + impl SocketDescriptorMock { + /// Basic unbounded implementation where send_data() will always succeed + fn new() -> Self { + Self { + unbounded: Rc::new(RefCell::new(true)), + send_recording: Rc::new(RefCell::new(Vec::new())), + free_space: Rc::new(RefCell::new(0)) + } + } + + /// Used for tests that want to return partial sends after a certain amount of data is sent through send_data() + fn with_fixed_size(limit: usize) -> Self { + let mut descriptor = Self::new(); + descriptor.unbounded = Rc::new(RefCell::new(false)); + descriptor.free_space = Rc::new(RefCell::new(limit)); + + descriptor + } + + /// Standard Mock api to verify actual vs. expected calls + fn assert_called_with(&self, expectation: Vec<(Vec, bool)>) { + assert_eq!(expectation.as_slice(), self.send_recording.borrow().as_slice()) + } + + /// Allow future send_data() calls to succeed for the next added_room bytes. Not valid for + /// unbounded mock descriptors + fn make_room(&mut self, added_room: usize) { + assert!(!*self.unbounded.borrow()); + let mut free_space = self.free_space.borrow_mut(); + + *free_space += added_room; + } + } + + impl SocketDescriptor for SocketDescriptorMock { + fn send_data(&mut self, data: &[u8], resume_read: bool) -> usize { + self.send_recording.borrow_mut().push((data.to_vec(), resume_read)); + + let mut free_space = self.free_space.borrow_mut(); + + // Unbounded just flush everything + return if *self.unbounded.borrow() { + data.len() + } + // Bounded flush up to the free_space limit + else { + let write_len = cmp::min(data.len(), *free_space); + *free_space -= write_len; + write_len + } + } + + fn disconnect_socket(&mut self) { + unimplemented!() + } + } + + impl Clone for SocketDescriptorMock { + fn clone(&self) -> Self { + Self { + unbounded: self.unbounded.clone(), + send_recording: self.send_recording.clone(), + free_space: self.free_space.clone() + } + } + } + + impl PartialEq for SocketDescriptorMock { + fn eq(&self, o: &Self) -> bool { + Rc::ptr_eq(&self.send_recording, &o.send_recording) + } + } + impl Hash for SocketDescriptorMock { + fn hash(&self, state: &mut H) { + self.send_recording.as_ptr().hash(state) + } + } + + // Test that a try_flush_one() call with no queued data doesn't write anything + #[test] + fn empty_does_not_write() { + let mut descriptor = SocketDescriptorMock::new(); + let mut empty = OutboundQueue::new(10); + + assert!(empty.try_flush_one(&mut descriptor)); + descriptor.assert_called_with(vec![]); + + } + + // Test that try_flush_one() sends the push_back + #[test] + fn push_back_drain() { + let mut descriptor = SocketDescriptorMock::new(); + let mut queue = OutboundQueue::new(10); + + queue.push_back(vec![1]); + assert!(queue.try_flush_one(&mut descriptor)); + + descriptor.assert_called_with(vec![(vec![1], true)]); + } + + // Test that try_flush_one() sends just first push_back + #[test] + fn push_back_push_back_drain_drain() { + let mut descriptor = SocketDescriptorMock::new(); + let mut queue = OutboundQueue::new(10); + + queue.push_back(vec![1]); + queue.push_back(vec![2]); + assert!(queue.try_flush_one(&mut descriptor)); + + descriptor.assert_called_with(vec![(vec![1], true)]); + } + + // Test that descriptor that can't write all bytes returns valid response + #[test] + fn push_back_drain_partial() { + let mut descriptor = SocketDescriptorMock::with_fixed_size(1); + let mut queue = OutboundQueue::new(10); + + queue.push_back(vec![1, 2, 3]); + assert!(!queue.try_flush_one(&mut descriptor)); + + descriptor.assert_called_with(vec![(vec![1, 2, 3], true)]); + } + + // Test the bookkeeping for multiple partial writes + #[test] + fn push_back_drain_partial_drain_partial_try_flush_one() { + let mut descriptor = SocketDescriptorMock::with_fixed_size(1); + let mut queue = OutboundQueue::new(10); + + queue.push_back(vec![1, 2, 3]); + assert!(!queue.try_flush_one(&mut descriptor)); + + descriptor.make_room(1); + queue.unblock(); + assert!(!queue.try_flush_one(&mut descriptor)); + + descriptor.make_room(1); + queue.unblock(); + assert!(queue.try_flush_one(&mut descriptor)); + + descriptor.assert_called_with(vec![(vec![1, 2, 3], true), (vec![2, 3], true), (vec![3], true)]); + } + + #[test] + fn push_back_drain_blocks() { + let mut descriptor = SocketDescriptorMock::with_fixed_size(0); + let mut queue = OutboundQueue::new(10); + + // Fail write and move to blocked state + queue.push_back(vec![1, 2]); + assert!(!queue.try_flush_one(&mut descriptor)); + descriptor.assert_called_with(vec![(vec![1, 2], true)]); + + // Make room but don't signal + descriptor.make_room(1); + assert!(!queue.try_flush_one(&mut descriptor)); + assert!(queue.is_blocked()); + descriptor.assert_called_with(vec![(vec![1, 2], true)]); + + // Unblock and try again + queue.unblock(); + + // Partial write will succeed, but still move to blocked + assert!(!queue.try_flush_one(&mut descriptor)); + assert!(queue.is_blocked()); + descriptor.assert_called_with(vec![(vec![1, 2], true), (vec![1, 2], true)]); + + // Make room and signal which will succeed in writing the final piece + descriptor.make_room(1); + queue.unblock(); + assert!(queue.try_flush_one(&mut descriptor)); + assert!(!queue.is_blocked()); + descriptor.assert_called_with(vec![(vec![1, 2], true), (vec![1, 2], true), (vec![2], true)]); + } + + // Test resume_reading argument to send_data when queue is above soft limit + #[test] + fn push_back_above_limit_resume_reading_false() { + let mut descriptor = SocketDescriptorMock::with_fixed_size(10); + let mut queue = OutboundQueue::new(1); + + queue.push_back(vec![1]); + assert!(queue.try_flush_one(&mut descriptor)); + descriptor.assert_called_with(vec![(vec![1], false)]); + } + + // Test that push_back works above soft limit, but send_read() is informed of the correct state + #[test] + fn push_back_above_limit_is_ok() { + let mut descriptor = SocketDescriptorMock::with_fixed_size(10); + let mut queue = OutboundQueue::new(2); + + queue.push_back(vec![1]); + queue.push_back(vec![2]); + queue.push_back(vec![3]); + assert!(queue.try_flush_one(&mut descriptor)); + assert!(queue.try_flush_one(&mut descriptor)); + assert!(queue.try_flush_one(&mut descriptor)); + descriptor.assert_called_with(vec![(vec![1], false), (vec![2], false), (vec![3], true)]); + } + + // Test is_empty() + #[test] + fn is_empty() { + let mut descriptor = SocketDescriptorMock::with_fixed_size(10); + let mut queue = OutboundQueue::new(1); + assert!(queue.is_empty()); + + queue.push_back(vec![1]); + assert!(!queue.is_empty()); + + assert!(queue.try_flush_one(&mut descriptor)); + assert!(queue.is_empty()); + } + + // Test queue_space() + #[test] + fn queue_space() { + let mut descriptor = SocketDescriptorMock::with_fixed_size(10); + let mut queue = OutboundQueue::new(1); + + // below soft limit + assert_eq!(queue.queue_space(), 1); + + // at soft limit + queue.push_back(vec![1]); + assert_eq!(queue.queue_space(), 0); + + // above soft limit + queue.push_back(vec![2]); + assert_eq!(queue.queue_space(), 0); + + // at soft limit + assert!(queue.try_flush_one(&mut descriptor)); + assert_eq!(queue.queue_space(), 0); + + // below soft limt + assert!(queue.try_flush_one(&mut descriptor)); + assert_eq!(queue.queue_space(), 1); + } +} \ No newline at end of file From d2ac3f7e381f8f676c5f9d0b9ac3a738d0abd8cb Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Fri, 4 Sep 2020 14:32:46 -0700 Subject: [PATCH 71/96] refactor: Abstract Transport layer and test it Start moving the code that implements the Bolt8 transport layer into a separate testable module. This patch makes use of Rust's supported mocking pattern to create test doubles and leverage them to write simple unit tests for the public API of Transport. The end goal is a mockable Transport layer for easier testing of the PeerManager. --- fuzz/src/peer_crypt.rs | 1 + lightning/src/ln/peers/handler.rs | 489 +++++++++------------ lightning/src/ln/peers/handshake/mod.rs | 45 +- lightning/src/ln/peers/handshake/states.rs | 8 +- lightning/src/ln/peers/mod.rs | 9 + lightning/src/ln/peers/outbound_queue.rs | 100 +---- lightning/src/ln/peers/test_util.rs | 205 +++++++++ lightning/src/ln/peers/transport.rs | 257 +++++++++++ 8 files changed, 707 insertions(+), 407 deletions(-) create mode 100644 lightning/src/ln/peers/test_util.rs create mode 100644 lightning/src/ln/peers/transport.rs diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index a9f9d5b7b1c..76ccc18fbe6 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -6,6 +6,7 @@ use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey,SecretKey}; use lightning::ln::peers::conduit::Conduit; use lightning::ln::peers::handshake::PeerHandshake; +use lightning::ln::peers::transport::IPeerHandshake; use utils::test_logger; // Test structure used to generate "random" values based on input data. It is used throughout diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 6bc92f4bb36..431ac0d748d 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -12,7 +12,7 @@ use ln::features::InitFeatures; use ln::msgs; use ln::msgs::{ChannelMessageHandler, LightningError, RoutingMessageHandler}; use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; -use util::ser::{VecWriter, Writeable}; +use util::ser::{Writeable}; use ln::wire; use ln::wire::Encode; use util::byte_utils; @@ -29,12 +29,76 @@ use std::ops::Deref; use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::sha256::HashEngine as Sha256Engine; use bitcoin::hashes::{HashEngine, Hash}; -use ln::peers::handshake::PeerHandshake; -use ln::peers::conduit::Conduit; use ln::peers::outbound_queue::OutboundQueue; +use ln::peers::transport::Transport; const MSG_BUFF_SIZE: usize = 10; +/// Interface PeerHandler uses to interact with the Transport object +pub(super) trait ITransport { + /// Instantiate the new outbound Transport + fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self; + + /// Set up the Transport receiving any bytes that need to be sent to the peer + fn set_up_outbound(&mut self) -> Vec; + + /// Instantiate a new inbound Transport + fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self; + + /// Process input data similar to reading it off a descriptor directly. + fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result<(), String>; + + /// Returns true if the connection is established and encrypted messages can be sent. + fn is_ready_for_encryption(&self) -> bool; + + /// Encodes, encrypts, and enqueues a message to the outbound queue. Panics if the connection is + /// not established yet. + fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q); +} + + +/// Trait representing a container that allows enqueuing of Vec<[u8]> +pub(super) trait PayloadQueuer { + /// Enqueue item to the queue + fn push_back(&mut self, item: Vec); + + /// Returns true if the queue is empty + fn is_empty(&self) -> bool; + + /// Returns the amount of available space in queue + fn queue_space(&self) -> usize; +} + +/// Implement &mut PayloadQueuer passthroughs +impl<'a, T> PayloadQueuer for &'a mut T where + T: PayloadQueuer { + fn push_back(&mut self, item: Vec) { + T::push_back(self, item) + } + + fn is_empty(&self) -> bool { + T::is_empty(self) + } + + fn queue_space(&self) -> usize { + T::queue_space(self) + } +} + +/// Trait representing a container that can try to flush data through a SocketDescriptor +pub(super) trait SocketDescriptorFlusher { + /// Write previously enqueued data to the SocketDescriptor. A return of false indicates the + /// underlying SocketDescriptor could not fulfill the send_data() call and the blocked state + /// has been set. Use unblock() when the SocketDescriptor may have more room. + fn try_flush_one(&mut self, descriptor: &mut impl SocketDescriptor) -> bool; + + /// Clear the blocked state caused when a previous write failed + fn unblock(&mut self); + + /// Check if the container is in a blocked state + fn is_blocked(&self) -> bool; +} + /// Provides references to trait impls which handle different types of messages. pub struct MessageHandler where CM::Target: ChannelMessageHandler, @@ -114,126 +178,8 @@ enum InitSyncTracker{ NodesSyncing(PublicKey), } -/// Trait representing a container that allows enqueuing of Vec<[u8]> -pub(super) trait PayloadQueuer { - /// Enqueue item to the queue - fn push_back(&mut self, item: Vec); - - /// Returns true if the queue is empty - fn is_empty(&self) -> bool; - - /// Returns the amount of available space in queue - fn queue_space(&self) -> usize; -} - -/// Implement &mut PayloadQueuer passthroughs -impl<'a, T> PayloadQueuer for &'a mut T where - T: PayloadQueuer { - fn push_back(&mut self, item: Vec) { - T::push_back(self, item) - } - - fn is_empty(&self) -> bool { - T::is_empty(self) - } - - fn queue_space(&self) -> usize { - T::queue_space(self) - } -} - -/// Trait representing a container that can try to flush data through a SocketDescriptor -pub(super) trait SocketDescriptorFlusher { - /// Write previously enqueued data to the SocketDescriptor. A return of false indicates the - /// underlying SocketDescriptor could not fulfill the send_data() call and the blocked state - /// has been set. Use unblock() when the SocketDescriptor may have more room. - fn try_flush_one(&mut self, descriptor: &mut impl SocketDescriptor) -> bool; - - /// Clear the blocked state caused when a previous write failed - fn unblock(&mut self); - - /// Check if the container is in a blocked state - fn is_blocked(&self) -> bool; -} - -/// Implement &mut Flushable passthroughs -impl<'a, T> SocketDescriptorFlusher for &'a mut T where - T: SocketDescriptorFlusher { - fn try_flush_one(&mut self, descriptor: &mut impl SocketDescriptor) -> bool { - T::try_flush_one(self, descriptor) - } - - fn unblock(&mut self) { - T::unblock(self) - } - - fn is_blocked(&self) -> bool { - T::is_blocked(self) - } -} - -enum PeerState { - Authenticating(PeerHandshake), - Connected(Conduit), -} - -enum PeerDataProcessingDecision { - CompleteHandshake(PublicKey), - Continue, - Disconnect(PeerHandleError) -} - -impl PeerState { - fn is_ready_for_encryption(&self) -> bool { - match self { - &PeerState::Connected(_) => true, - _ => false - } - } - - fn process_peer_data(&mut self, data: &[u8], pending_outbound_buffer: &mut impl PayloadQueuer) -> PeerDataProcessingDecision { - let (new_state_opt, decision) = match self { - &mut PeerState::Authenticating(ref mut handshake) => { - match handshake.process_act(data) { - // Any errors originating from the handshake sequence result in Disconnect - Err(_e) => { - (None, PeerDataProcessingDecision::Disconnect(PeerHandleError { no_connection_possible: false })) - }, - // Otherwise, handshake may or may not be complete depending on whether or not - // we receive a (conduit, pubkey) - Ok((response_vec_option, conduit_and_remote_static_public_key_option)) => { - - // Any response generated by the handshake sequence is put into the response buffer - if let Some(response_vec) = response_vec_option { - pending_outbound_buffer.push_back(response_vec); - } - - // if process_act() returns the conduit and remote static public key (node id) - // the handshake is complete - if let Some((conduit, remote_static_public_key)) = conduit_and_remote_static_public_key_option { - (Some(PeerState::Connected(conduit)), PeerDataProcessingDecision::CompleteHandshake(remote_static_public_key)) - } else { - (None, PeerDataProcessingDecision::Continue) - } - } - } - }, - &mut PeerState::Connected(ref mut conduit) => { - conduit.read(data); - (None, PeerDataProcessingDecision::Continue) - } - }; - - if let Some(new_state) = new_state_opt { - *self = new_state; - } - - decision - } -} - struct Peer { - encryptor: PeerState, + transport: Transport, outbound: bool, their_node_id: Option, their_features: Option, @@ -342,14 +288,6 @@ impl From for MessageHandlingError { } } -macro_rules! encode_msg { - ($msg: expr) => {{ - let mut buffer = VecWriter(Vec::new()); - wire::write($msg, &mut buffer).unwrap(); - buffer.0 - }} -} - /// Manages and reacts to connection events. You probably want to use file descriptors as PeerIds. /// PeerIds may repeat, but only after socket_disconnected() has been called. impl PeerManager where @@ -386,7 +324,7 @@ impl PeerManager Vec { let peers = self.peers.lock().unwrap(); peers.peers.values().filter_map(|p| { - if !p.encryptor.is_ready_for_encryption() || p.their_features.is_none() { + if !p.transport.is_ready_for_encryption() || p.their_features.is_none() { return None; } p.their_node_id @@ -415,12 +353,12 @@ impl PeerManager Result, PeerHandleError> { - let mut handshake = PeerHandshake::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); - let initial_bytes = handshake.set_up_outbound(); - let mut peers = self.peers.lock().unwrap(); + let mut transport = Transport::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); + let initial_bytes = transport.set_up_outbound(); + if peers.peers.insert(descriptor, Peer { - encryptor: PeerState::Authenticating(handshake), + transport, outbound: true, their_node_id: Some(their_node_id.clone()), their_features: None, @@ -446,11 +384,9 @@ impl PeerManager Result<(), PeerHandleError> { - let handshake = PeerHandshake::new_inbound(&self.our_node_secret, &self.get_ephemeral_key()); - let mut peers = self.peers.lock().unwrap(); if peers.peers.insert(descriptor, Peer { - encryptor: PeerState::Authenticating(handshake), + transport: Transport::new_inbound(&self.our_node_secret, &self.get_ephemeral_key()), outbound: false, their_node_id: None, their_features: None, @@ -467,14 +403,12 @@ impl PeerManager { { log_trace!(self.logger, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - match peer.encryptor { - PeerState::Connected(ref mut conduit) => peer.pending_outbound_buffer.push_back(conduit.encrypt(&encode_msg!($msg)[..])), - _ => panic!("peer must be connected!") - } + assert!(peer.transport.is_ready_for_encryption()); + peer.transport.enqueue_message($msg, &mut peer.pending_outbound_buffer) } } } @@ -488,12 +422,12 @@ impl PeerManager PeerManager PeerManager PeerManager(&self, peers_needing_send: &mut HashSet, peer: &mut Peer, descriptor: Descriptor, message: &M) { - let mut buffer = VecWriter(Vec::new()); - wire::write(message, &mut buffer).unwrap(); // crash if the write failed - let encoded_message = buffer.0; - log_trace!(self.logger, "Enqueueing message of type {} to {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - match peer.encryptor { - PeerState::Connected(ref mut conduit) => peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_message[..])), - _ => panic!("peer must be connected!") - } + peer.transport.enqueue_message(message, &mut peer.pending_outbound_buffer); peers_needing_send.insert(descriptor); } @@ -602,89 +529,98 @@ impl PeerManager panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => { - let data_processing_decision = peer.encryptor.process_peer_data(data, &mut peer.pending_outbound_buffer); - match data_processing_decision { - PeerDataProcessingDecision::Disconnect(e) => { - log_trace!(self.logger, "Invalid act message; disconnecting: {}", e); - return Err(e); - } - - PeerDataProcessingDecision::CompleteHandshake(remote_pubkey) => { - peer.their_node_id = Some(remote_pubkey); + match peer.transport.process_input(data, &mut peer.pending_outbound_buffer) { + Err(e) => { + log_trace!(self.logger, "Error while processing input: {}", e); + return Err(PeerHandleError { no_connection_possible: false }) + }, + Ok(_) => { + + // If the transport is newly connected, do the appropriate set up for the connection + if peer.transport.is_ready_for_encryption() { + let their_node_id = peer.transport.their_node_id.unwrap(); + + match peers.node_id_to_descriptor.entry(their_node_id.clone()) { + hash_map::Entry::Occupied(entry) => { + if entry.get() != peer_descriptor { + // Existing entry in map is from a different descriptor, this is a duplicate + log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(&their_node_id)); + peer.their_node_id = None; + return Err(PeerHandleError { no_connection_possible: false }); + } else { + // read_event for existing peer + } + }, + hash_map::Entry::Vacant(entry) => { + log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&their_node_id)); + peer.their_node_id = Some(their_node_id.clone()); + + if peer.outbound { + let mut features = InitFeatures::known(); + if !self.message_handler.route_handler.should_request_full_sync(&their_node_id) { + features.clear_initial_routing_sync(); + } - if peer.outbound { - let mut features = InitFeatures::known(); - if !self.message_handler.route_handler.should_request_full_sync(&peer.their_node_id.unwrap()) { - features.clear_initial_routing_sync(); + let resp = msgs::Init { features }; + self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); + } + entry.insert(peer_descriptor.clone()); + } } - - let resp = msgs::Init { features }; - self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &resp); } - - // insert node id - match peers.node_id_to_descriptor.entry(peer.their_node_id.unwrap()) { - hash_map::Entry::Occupied(_) => { - log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(peer.their_node_id.unwrap())); - peer.their_node_id = None; // Unset so that we don't generate a peer_disconnected event - return Err(PeerHandleError { no_connection_possible: false }); - } - hash_map::Entry::Vacant(entry) => { - log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(peer.their_node_id.unwrap())); - entry.insert(peer_descriptor.clone()) - } - }; } - _ => { } - }; + } let mut received_messages = vec![]; - if let &mut PeerState::Connected(ref mut conduit) = &mut peer.encryptor { - // Using Iterators that can error requires special handling - // The item returned from next() has type Option, String>> - // The Some wrapper is stripped for each item inside the loop - // There are 3 valid match cases: - // 1) Some(Ok(Some(msg_data))) => Indicates a valid decrypted msg accessed via msg_data - // 2) Some(Err(_)) => Indicates an error during decryption that should be handled - // 3) None -> Indicates there were no messages available to decrypt - // Invalid Cases - // 1) Some(Ok(None)) => Translated to None case above so users of iterators can stop correctly - for msg_data_result in &mut conduit.decryptor { - match msg_data_result { - Ok(Some(msg_data)) => { - let mut reader = ::std::io::Cursor::new(&msg_data[..]); - let message_result = wire::read(&mut reader); - let message = match message_result { - Ok(x) => x, - Err(e) => { - match e { - msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(self.logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); - continue; - } - msgs::DecodeError::InvalidValue => { - log_debug!(self.logger, "Got an invalid value while deserializing message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ShortRead => { - log_debug!(self.logger, "Deserialization failed due to shortness of message"); - return Err(PeerHandleError { no_connection_possible: false }); + match peer.transport.conduit { + None => { } + Some(ref mut conduit) => { + // Using Iterators that can error requires special handling + // The item returned from next() has type Option, String>> + // The Some wrapper is stripped for each item inside the loop + // There are 3 valid match cases: + // 1) Some(Ok(Some(msg_data))) => Indicates a valid decrypted msg accessed via msg_data + // 2) Some(Err(_)) => Indicates an error during decryption that should be handled + // 3) None -> Indicates there were no messages available to decrypt + // Invalid Cases + // 1) Some(Ok(None)) => Translated to None case above so users of iterators can stop correctly + for msg_data_result in &mut conduit.decryptor { + match msg_data_result { + Ok(Some(msg_data)) => { + let mut reader = ::std::io::Cursor::new(&msg_data[..]); + let message_result = wire::read(&mut reader); + let message = match message_result { + Ok(x) => x, + Err(e) => { + match e { + msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::UnknownRequiredFeature => { + log_debug!(self.logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + continue; + } + msgs::DecodeError::InvalidValue => { + log_debug!(self.logger, "Got an invalid value while deserializing message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ShortRead => { + log_debug!(self.logger, "Deserialization failed due to shortness of message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), } - msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), } - } - }; + }; - received_messages.push(message); - }, - Err(e) => { - log_trace!(self.logger, "Message decryption failed due to: {}", e); - return Err(PeerHandleError { no_connection_possible: false }); - } - Ok(None) => { - panic!("Invalid behavior. Conduit iterator should never return this match.") + received_messages.push(message); + }, + Err(e) => { + log_trace!(self.logger, "Message decryption failed due to: {}", e); + return Err(PeerHandleError { no_connection_possible: false }); + } + Ok(None) => { + panic!("Invalid behavior. Conduit iterator should never return this match.") + } } } } @@ -970,8 +906,8 @@ impl PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager { log_trace!(self.logger, "Handling BroadcastChannelAnnouncement event in peer_handler for short channel id {}", msg.contents.short_channel_id); if self.message_handler.route_handler.handle_channel_announcement(msg).is_ok() && self.message_handler.route_handler.handle_channel_update(update_msg).is_ok() { - let encoded_msg = encode_msg!(msg); - let encoded_update_msg = encode_msg!(update_msg); - for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.encryptor.is_ready_for_encryption() || peer.their_features.is_none() || + if !peer.transport.is_ready_for_encryption() || peer.their_features.is_none() || !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { continue } @@ -1136,9 +1069,9 @@ impl PeerManager PeerManager { log_trace!(self.logger, "Handling BroadcastNodeAnnouncement event in peer_handler"); if self.message_handler.route_handler.handle_node_announcement(msg).is_ok() { - let encoded_msg = encode_msg!(msg); - for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.encryptor.is_ready_for_encryption() || peer.their_features.is_none() || + if !peer.transport.is_ready_for_encryption() || peer.their_features.is_none() || !peer.should_forward_node_announcement(msg.contents.node_id) { continue } - if let PeerState::Connected(ref mut conduit) = peer.encryptor { - peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_msg[..])); + if peer.transport.is_ready_for_encryption() { + peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer); } self.do_attempt_write_data(&mut (*descriptor).clone(), peer); } @@ -1164,15 +1095,13 @@ impl PeerManager { log_trace!(self.logger, "Handling BroadcastChannelUpdate event in peer_handler for short channel id {}", msg.contents.short_channel_id); if self.message_handler.route_handler.handle_channel_update(msg).is_ok() { - let encoded_msg = encode_msg!(msg); - for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.encryptor.is_ready_for_encryption() || peer.their_features.is_none() || + if !peer.transport.is_ready_for_encryption() || peer.their_features.is_none() || !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { continue } - if let PeerState::Connected(ref mut conduit) = peer.encryptor { - peer.pending_outbound_buffer.push_back(conduit.encrypt(&encoded_msg[..])); + if peer.transport.is_ready_for_encryption() { + peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer); } self.do_attempt_write_data(&mut (*descriptor).clone(), peer); } @@ -1191,8 +1120,8 @@ impl PeerManager PeerManager PeerManager Result<(Option, HandshakeState), String>; +} + /// Object for managing handshakes. /// Currently requires explicit ephemeral private key specification. pub struct PeerHandshake { @@ -17,10 +27,10 @@ pub struct PeerHandshake { ready_to_process: bool, } -impl PeerHandshake { +impl IPeerHandshake for PeerHandshake { /// Instantiate a handshake given the peer's static public key. The ephemeral private key MUST /// generate a new session with strong cryptographic randomness. - pub fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { + fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { let state = HandshakeState::new_initiator(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key); Self { @@ -29,16 +39,8 @@ impl PeerHandshake { } } - /// Instantiate a handshake in anticipation of a peer's first handshake act - pub fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { - Self { - state: Some(HandshakeState::new_responder(responder_static_private_key, responder_ephemeral_private_key)), - ready_to_process: true, - } - } - /// Initializes the outbound handshake and provides the initial bytes to send to the responder - pub fn set_up_outbound(&mut self) -> Vec { + fn set_up_outbound(&mut self) -> Vec { assert!(!self.ready_to_process); self.ready_to_process = true; @@ -49,6 +51,14 @@ impl PeerHandshake { response_vec_option.unwrap() } + /// Instantiate a new handshake in anticipation of a peer's first handshake act + fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { + Self { + state: Some(HandshakeState::new_responder(responder_static_private_key, responder_ephemeral_private_key)), + ready_to_process: true, + } + } + /// Process act dynamically /// # Arguments /// `input`: Byte slice received from peer as part of the handshake protocol @@ -57,7 +67,7 @@ impl PeerHandshake { /// Returns a tuple with the following components: /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol /// `.1`: Some(Conduit, PublicKey) if the handshake was just processed to completion and messages can now be encrypted and decrypted - pub fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { assert!(self.ready_to_process); let cur_state = self.state.take().unwrap(); @@ -120,15 +130,6 @@ mod test { } } - macro_rules! assert_matches { - ($e:expr, $state_match:pat) => { - match $e { - $state_match => (), - _ => panic!() - } - } - } - macro_rules! do_process_act_or_panic { ($handshake:expr, $input:expr) => { $handshake.process_act($input).unwrap().0.unwrap() diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index b116349defc..00962346eaa 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -7,6 +7,7 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::{chacha, hkdf5869rfc}; use ln::peers::conduit::{Conduit, SymmetricKey}; use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; +use ln::peers::handshake::IHandshakeState; // Alias type to help differentiate between temporary key and chaining key when passing bytes around type ChainingKey = [u8; 32]; @@ -30,13 +31,6 @@ pub(super) enum HandshakeState { Complete(Option<(Conduit, PublicKey)>), } -// Trait for all individual states to implement that ensure HandshakeState::next() can -// delegate to a common function signature. May transition to the same state in the event there are -// not yet enough bytes to move forward with the handshake. -pub(super) trait IHandshakeState { - fn next(self, input: &[u8]) -> Result<(Option, HandshakeState), String>; -} - // Enum dispatch for state machine. Single public interface can statically dispatch to all states impl HandshakeState { pub(super) fn new_initiator(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index 9de3fcb072b..6086352e2a1 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -3,6 +3,10 @@ //! When a handshake completes, it returns an instance of Conduit. //! Conduit enables message encryption and decryption, and automatically handles key rotation. +#[cfg(test)] +#[macro_use] +mod test_util; + mod chacha; pub mod handler; mod hkdf5869rfc; @@ -17,3 +21,8 @@ mod conduit; pub mod handshake; #[cfg(not(feature = "fuzztarget"))] mod handshake; + +#[cfg(feature = "fuzztarget")] +pub mod transport; +#[cfg(not(feature = "fuzztarget"))] +mod transport; diff --git a/lightning/src/ln/peers/outbound_queue.rs b/lightning/src/ln/peers/outbound_queue.rs index 5214ba21234..501a4756524 100644 --- a/lightning/src/ln/peers/outbound_queue.rs +++ b/lightning/src/ln/peers/outbound_queue.rs @@ -28,6 +28,7 @@ impl PayloadQueuer for OutboundQueue { self.soft_limit - cmp::min(self.soft_limit, self.buffer.len()) } } + impl SocketDescriptorFlusher for OutboundQueue { fn try_flush_one(&mut self, descriptor: &mut impl SocketDescriptor) -> bool { // Exit early if a previous full write failed and haven't heard that there may be more @@ -83,104 +84,7 @@ impl OutboundQueue { #[cfg(test)] mod tests { use super::*; - use std::rc::Rc; - use std::cell::RefCell; - use std::hash::Hash; - use std::cmp; - - /// Mock implementation of the SocketDescriptor trait that can be used in tests to finely control - /// the send_data() behavior. - /// - ///Additionally, records the actual calls to send_data() for later validation. - #[derive(Debug, Eq)] - struct SocketDescriptorMock { - /// If true, all send_data() calls will succeed - unbounded: Rc>, - - /// Amount of free space in the descriptor for send_data() bytes - free_space: Rc>, - - /// Vector of arguments and return values to send_data() used for validation - send_recording: Rc, bool)>>>, - } - - impl SocketDescriptorMock { - /// Basic unbounded implementation where send_data() will always succeed - fn new() -> Self { - Self { - unbounded: Rc::new(RefCell::new(true)), - send_recording: Rc::new(RefCell::new(Vec::new())), - free_space: Rc::new(RefCell::new(0)) - } - } - - /// Used for tests that want to return partial sends after a certain amount of data is sent through send_data() - fn with_fixed_size(limit: usize) -> Self { - let mut descriptor = Self::new(); - descriptor.unbounded = Rc::new(RefCell::new(false)); - descriptor.free_space = Rc::new(RefCell::new(limit)); - - descriptor - } - - /// Standard Mock api to verify actual vs. expected calls - fn assert_called_with(&self, expectation: Vec<(Vec, bool)>) { - assert_eq!(expectation.as_slice(), self.send_recording.borrow().as_slice()) - } - - /// Allow future send_data() calls to succeed for the next added_room bytes. Not valid for - /// unbounded mock descriptors - fn make_room(&mut self, added_room: usize) { - assert!(!*self.unbounded.borrow()); - let mut free_space = self.free_space.borrow_mut(); - - *free_space += added_room; - } - } - - impl SocketDescriptor for SocketDescriptorMock { - fn send_data(&mut self, data: &[u8], resume_read: bool) -> usize { - self.send_recording.borrow_mut().push((data.to_vec(), resume_read)); - - let mut free_space = self.free_space.borrow_mut(); - - // Unbounded just flush everything - return if *self.unbounded.borrow() { - data.len() - } - // Bounded flush up to the free_space limit - else { - let write_len = cmp::min(data.len(), *free_space); - *free_space -= write_len; - write_len - } - } - - fn disconnect_socket(&mut self) { - unimplemented!() - } - } - - impl Clone for SocketDescriptorMock { - fn clone(&self) -> Self { - Self { - unbounded: self.unbounded.clone(), - send_recording: self.send_recording.clone(), - free_space: self.free_space.clone() - } - } - } - - impl PartialEq for SocketDescriptorMock { - fn eq(&self, o: &Self) -> bool { - Rc::ptr_eq(&self.send_recording, &o.send_recording) - } - } - impl Hash for SocketDescriptorMock { - fn hash(&self, state: &mut H) { - self.send_recording.as_ptr().hash(state) - } - } + use ln::peers::test_util::*; // Test that a try_flush_one() call with no queued data doesn't write anything #[test] diff --git a/lightning/src/ln/peers/test_util.rs b/lightning/src/ln/peers/test_util.rs new file mode 100644 index 00000000000..e384317ae34 --- /dev/null +++ b/lightning/src/ln/peers/test_util.rs @@ -0,0 +1,205 @@ +/// Test library for test doubles used in the various peers unit tests + +use bitcoin::secp256k1; +use bitcoin::secp256k1::key::{PublicKey, SecretKey}; + +use ln::peers::conduit::Conduit; +use ln::peers::handler::{SocketDescriptor, PayloadQueuer}; +use ln::peers::transport::IPeerHandshake; + +use std::rc::Rc; +use std::cell::RefCell; +use std::hash::Hash; +use std::cmp; + +macro_rules! assert_matches { + ($actual:expr, $expected:pat) => { + match $actual { + $expected => (), + _ => panic!() + } + } +} + +/// Stub implementation of IPeerHandshake that returns an error for process_act() +pub(super) struct PeerHandshakeTestStubFail { } + +impl IPeerHandshake for PeerHandshakeTestStubFail { + fn new_outbound(_initiator_static_private_key: &SecretKey, _responder_static_public_key: &PublicKey, _initiator_ephemeral_private_key: &SecretKey) -> Self { + PeerHandshakeTestStubFail { } + } + + fn set_up_outbound(&mut self) -> Vec { + vec![] + } + + fn new_inbound(_responder_static_private_key: &SecretKey, _responder_ephemeral_private_key: &SecretKey) -> Self { + PeerHandshakeTestStubFail { } + } + + fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + Err("Oh no!".to_string()) + } +} + +/// Stub implementation of IPeerHandshake that returns &[1] from process_act() +pub(super) struct PeerHandshakeTestStubBytes { } + +impl PeerHandshakeTestStubBytes { + pub(crate) const RETURNED_BYTES: [u8; 1] = [1]; +} + +impl IPeerHandshake for PeerHandshakeTestStubBytes { + + fn new_outbound(_initiator_static_private_key: &SecretKey, _responder_static_public_key: &PublicKey, _initiator_ephemeral_private_key: &SecretKey) -> Self { + PeerHandshakeTestStubBytes { } + } + + fn set_up_outbound(&mut self) -> Vec { + vec![] + } + + fn new_inbound(_responder_static_private_key: &SecretKey, _responder_ephemeral_private_key: &SecretKey) -> Self { + PeerHandshakeTestStubBytes { } + } + + fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + Ok((Some(Self::RETURNED_BYTES[..].to_vec()), None)) + } +} + +/// Stub implementation of IPeerhandshake that returns Some(Conduit, PublicKey) +pub(super) struct PeerHandshakeTestStubComplete { } + +impl IPeerHandshake for PeerHandshakeTestStubComplete { + fn new_outbound(_initiator_static_private_key: &SecretKey, _responder_static_public_key: &PublicKey, _initiator_ephemeral_private_key: &SecretKey) -> Self { + PeerHandshakeTestStubComplete { } + } + + fn set_up_outbound(&mut self) -> Vec { + vec![] + } + + fn new_inbound(_responder_static_private_key: &SecretKey, _responder_ephemeral_private_key: &SecretKey) -> Self { + PeerHandshakeTestStubComplete { } + } + + fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + let curve = secp256k1::Secp256k1::new(); + let private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let public_key = PublicKey::from_secret_key(&curve, &private_key); + let conduit = Conduit::new([0;32], [0;32], [0;32]); + + Ok((None, Some((conduit, public_key)))) + } +} + +/// Mock implementation of the SocketDescriptor trait that can be used in tests to finely control +/// the send_data() behavior. +/// +/// Additionally, records the actual calls to send_data() for later validation. +#[derive(Debug, Eq)] +pub(super) struct SocketDescriptorMock { + /// If true, all send_data() calls will succeed + unbounded: Rc>, + + /// Amount of free space in the descriptor for send_data() bytes + free_space: Rc>, + + /// Vector of arguments and return values to send_data() used for validation + send_recording: Rc, bool)>>>, +} + +impl SocketDescriptorMock { + /// Basic unbounded implementation where send_data() will always succeed + pub(super) fn new() -> Self { + Self { + unbounded: Rc::new(RefCell::new(true)), + send_recording: Rc::new(RefCell::new(Vec::new())), + free_space: Rc::new(RefCell::new(0)) + } + } + + /// Used for tests that want to return partial sends after a certain amount of data is sent through send_data() + pub(super) fn with_fixed_size(limit: usize) -> Self { + let mut descriptor = Self::new(); + descriptor.unbounded = Rc::new(RefCell::new(false)); + descriptor.free_space = Rc::new(RefCell::new(limit)); + + descriptor + } + + /// Standard Mock api to verify actual vs. expected calls + pub(super) fn assert_called_with(&self, expectation: Vec<(Vec, bool)>) { + assert_eq!(expectation.as_slice(), self.send_recording.borrow().as_slice()) + } + + /// Allow future send_data() calls to succeed for the next added_room bytes. Not valid for + /// unbounded mock descriptors + pub(super) fn make_room(&mut self, added_room: usize) { + assert!(!*self.unbounded.borrow()); + let mut free_space = self.free_space.borrow_mut(); + + *free_space += added_room; + } +} + +impl SocketDescriptor for SocketDescriptorMock { + fn send_data(&mut self, data: &[u8], resume_read: bool) -> usize { + self.send_recording.borrow_mut().push((data.to_vec(), resume_read)); + + let mut free_space = self.free_space.borrow_mut(); + + // Unbounded just flush everything + return if *self.unbounded.borrow() { + data.len() + } + // Bounded flush up to the free_space limit + else { + let write_len = cmp::min(data.len(), *free_space); + *free_space -= write_len; + write_len + } + } + + fn disconnect_socket(&mut self) { + unimplemented!() + } +} + +impl Clone for SocketDescriptorMock { + fn clone(&self) -> Self { + Self { + unbounded: self.unbounded.clone(), + send_recording: self.send_recording.clone(), + free_space: self.free_space.clone() + } + } +} + +impl PartialEq for SocketDescriptorMock { + fn eq(&self, o: &Self) -> bool { + Rc::ptr_eq(&self.send_recording, &o.send_recording) + } +} +impl Hash for SocketDescriptorMock { + fn hash(&self, state: &mut H) { + self.send_recording.as_ptr().hash(state) + } +} + +/// Implement PayloadQueuer for Vec> so it can be used as a Spy in tests +impl PayloadQueuer for Vec> { + fn push_back(&mut self, item: Vec) { + self.push(item) + } + + fn is_empty(&self) -> bool { + self.is_empty() + } + + fn queue_space(&self) -> usize { + unimplemented!() + } +} + diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs new file mode 100644 index 00000000000..67d34eedbf7 --- /dev/null +++ b/lightning/src/ln/peers/transport.rs @@ -0,0 +1,257 @@ +/// Abstraction for the transport layer as described by Bolt #8 [https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md] + +use bitcoin::secp256k1::{SecretKey, PublicKey}; + +use ln::peers::conduit::Conduit; +use ln::peers::handler::{ITransport, PayloadQueuer}; +use ln::peers::handshake::PeerHandshake; +use ln::wire; +use ln::wire::Encode; + +use util::ser::{Writeable, VecWriter}; + +/// Interface used by Transport to interact with a handshake object +pub trait IPeerHandshake { + /// Instantiate a new outbound handshake + fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self; + + /// Set up the handshake receiving any bytes that need to be sent to the peer + fn set_up_outbound(&mut self) -> Vec; + + /// Instantiate a new inbound handshake + fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self; + + /// Progress the handshake given bytes received from the peer. Returns Some(Conduit, PublicKey) when the handshake + /// is complete. + fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String>; +} + +pub(super) struct Transport { + pub(super) conduit: Option, + handshake: PeerHandshakeImpl, + pub(super) their_node_id: Option, +} + +impl ITransport for Transport { + fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { + Self { + conduit: None, + handshake: PeerHandshakeImpl::new_outbound(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key), + their_node_id: None, + } + } + + fn set_up_outbound(&mut self) -> Vec { + self.handshake.set_up_outbound().to_vec() + } + + fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self { + Self { + conduit: None, + handshake: PeerHandshakeImpl::new_inbound(responder_static_private_key, responder_ephemeral_private_key), + their_node_id: None, + } + } + + fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result<(), String> { + match self.conduit { + // Continue handshake + None => { + let (response_option, conduit_and_remote_pubkey_option) = self.handshake.process_act(input)?; + + // Any response generated by the handshake sequence is put into the response buffer + if let Some(response) = response_option { + output_buffer.push_back(response.to_vec()); + } + + // If handshake is complete change the state + if let Some((conduit, remote_pubkey)) = conduit_and_remote_pubkey_option { + self.conduit = Some(conduit); + self.their_node_id = Some(remote_pubkey); + } + } + Some(ref mut conduit) => { + conduit.read(input); + } + }; + + Ok(()) + } + + fn is_ready_for_encryption(&self) -> bool { + self.conduit.is_some() + } + + fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q) { + match self.conduit { + None => panic!("Enqueueing messages only supported after transport is connected"), + Some(ref mut conduit) => { + let mut buffer = VecWriter(Vec::new()); + wire::write(message, &mut buffer).unwrap(); + output_buffer.push_back(conduit.encrypt(&buffer.0)); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use ln::peers::test_util::*; + + use bitcoin::secp256k1; + use bitcoin::secp256k1::key::{PublicKey, SecretKey}; + use ln::msgs; + + fn create_outbound_for_test() -> Transport { + let curve = secp256k1::Secp256k1::new(); + let outbound_static_private_key = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let outbound_ephemeral_private_key = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); + let inbound_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let inbound_static_public_key = PublicKey::from_secret_key(&curve, &inbound_static_private_key); + + Transport::::new_outbound(&outbound_static_private_key, &inbound_static_public_key, &outbound_ephemeral_private_key) + } + + fn create_inbound_for_test() -> Transport { + let inbound_static_private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); + let inbound_ephemeral_private_key = SecretKey::from_slice(&[0x_22_u8; 32]).unwrap(); + + Transport::::new_inbound(&inbound_static_private_key, &inbound_ephemeral_private_key) + } + + // Test initial states start off unconnected + #[test] + fn inbound_unconnected() { + let transport = create_inbound_for_test::(); + + assert!(!transport.is_ready_for_encryption()); + } + + #[test] + fn outbound_unconnected() { + let mut transport = create_outbound_for_test::(); + transport.set_up_outbound(); + + assert!(!transport.is_ready_for_encryption()); + } + + // Test that errors in the handshake code are reraised through the transport + #[test] + fn inbound_handshake_error_reraises() { + let mut transport = create_inbound_for_test::(); + let mut spy = Vec::new(); + + assert_eq!(transport.process_input(&[], &mut spy).err(), Some("Oh no!".to_string())); + } + + #[test] + fn outbound_handshake_error_reraises() { + let mut transport = create_outbound_for_test::(); + let mut spy = Vec::new(); + + assert_eq!(transport.process_input(&[], &mut spy).err(), Some("Oh no!".to_string())); + } + + #[test] + fn inbound_handshake_data_goes_to_queue() { + let mut transport = create_inbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + assert!(!transport.is_ready_for_encryption()); + + assert_matches!(&spy[..], [_]); + } + + // Test that data returned from the in-progress handshake code makes it through to the outbound buffer + #[test] + fn outbound_handshake_data_goes_to_queue() { + let mut transport = create_outbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + assert!(!transport.is_ready_for_encryption()); + + assert_matches!(&spy[..], [_]); + } + + #[test] + fn inbound_handshake_complete_ready_for_encryption() { + let mut transport = create_inbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + assert!(transport.is_ready_for_encryption()); + } + + // Test that when a handshake completes is_ready_for_encryption() is correct + #[test] + fn outbound_handshake_complete_ready_for_encryption() { + let mut transport = create_outbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + assert!(transport.is_ready_for_encryption()); + } + + #[test] + #[should_panic(expected = "Enqueueing messages only supported after transport is connected")] + fn inbound_enqueue_message_panic() { + let mut transport = create_inbound_for_test::(); + let mut spy = Vec::new(); + + let ping = msgs::Ping { + ponglen: 0, + byteslen: 64, + }; + transport.enqueue_message(&ping, &mut spy); + } + + // Test that enqueue_message() panics in the wrong state + #[test] + #[should_panic(expected = "Enqueueing messages only supported after transport is connected")] + fn outbound_enqueue_message_panic() { + let mut transport = create_outbound_for_test::(); + let mut spy = Vec::new(); + + let ping = msgs::Ping { + ponglen: 0, + byteslen: 64, + }; + transport.enqueue_message(&ping, &mut spy); + } + + // Test that enqueue_message() puts something into the outbound buffer + #[test] + fn inbound_enqueue_message_encrypts() { + let mut transport = create_inbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + + let ping = msgs::Ping { + ponglen: 0, + byteslen: 64, + }; + transport.enqueue_message(&ping, &mut spy); + + assert_matches!(&spy[..], [_]); + } + + #[test] + fn outbound_enqueue_message_encrypts() { + let mut transport = create_outbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + + let ping = msgs::Ping { + ponglen: 0, + byteslen: 64, + }; + transport.enqueue_message(&ping, &mut spy); + + assert_matches!(&spy[..], [_]); + } +} \ No newline at end of file From 96296fc0a80cd3f9ea7fde28ae3a0965d0f4723d Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 1 Sep 2020 13:58:39 -0700 Subject: [PATCH 72/96] rename: s/is_ready_for_encryption/is_connected/g --- lightning/src/ln/peers/handler.rs | 50 ++++++++++++++--------------- lightning/src/ln/peers/transport.rs | 16 ++++----- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 431ac0d748d..45148ad0cbc 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -49,7 +49,7 @@ pub(super) trait ITransport { fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result<(), String>; /// Returns true if the connection is established and encrypted messages can be sent. - fn is_ready_for_encryption(&self) -> bool; + fn is_connected(&self) -> bool; /// Encodes, encrypts, and enqueues a message to the outbound queue. Panics if the connection is /// not established yet. @@ -324,7 +324,7 @@ impl PeerManager Vec { let peers = self.peers.lock().unwrap(); peers.peers.values().filter_map(|p| { - if !p.transport.is_ready_for_encryption() || p.their_features.is_none() { + if !p.transport.is_connected() || p.their_features.is_none() { return None; } p.their_node_id @@ -407,7 +407,7 @@ impl PeerManager { { log_trace!(self.logger, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - assert!(peer.transport.is_ready_for_encryption()); + assert!(peer.transport.is_connected()); peer.transport.enqueue_message($msg, &mut peer.pending_outbound_buffer) } } @@ -537,7 +537,7 @@ impl PeerManager { // If the transport is newly connected, do the appropriate set up for the connection - if peer.transport.is_ready_for_encryption() { + if peer.transport.is_connected() { let their_node_id = peer.transport.their_node_id.unwrap(); match peers.node_id_to_descriptor.entry(their_node_id.clone()) { @@ -906,7 +906,7 @@ impl PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager { // This can't actually happen as we should have hit - // is_ready_for_encryption() previously on this same peer. + // is_connected() previously on this same peer. unreachable!(); }, } @@ -1224,7 +1224,7 @@ impl PeerManager ITransport for Transport bool { + fn is_connected(&self) -> bool { self.conduit.is_some() } @@ -125,7 +125,7 @@ mod tests { fn inbound_unconnected() { let transport = create_inbound_for_test::(); - assert!(!transport.is_ready_for_encryption()); + assert!(!transport.is_connected()); } #[test] @@ -133,7 +133,7 @@ mod tests { let mut transport = create_outbound_for_test::(); transport.set_up_outbound(); - assert!(!transport.is_ready_for_encryption()); + assert!(!transport.is_connected()); } // Test that errors in the handshake code are reraised through the transport @@ -159,7 +159,7 @@ mod tests { let mut spy = Vec::new(); transport.process_input(&[], &mut spy).unwrap(); - assert!(!transport.is_ready_for_encryption()); + assert!(!transport.is_connected()); assert_matches!(&spy[..], [_]); } @@ -171,7 +171,7 @@ mod tests { let mut spy = Vec::new(); transport.process_input(&[], &mut spy).unwrap(); - assert!(!transport.is_ready_for_encryption()); + assert!(!transport.is_connected()); assert_matches!(&spy[..], [_]); } @@ -182,17 +182,17 @@ mod tests { let mut spy = Vec::new(); transport.process_input(&[], &mut spy).unwrap(); - assert!(transport.is_ready_for_encryption()); + assert!(transport.is_connected()); } - // Test that when a handshake completes is_ready_for_encryption() is correct + // Test that when a handshake completes is_connected() is correct #[test] fn outbound_handshake_complete_ready_for_encryption() { let mut transport = create_outbound_for_test::(); let mut spy = Vec::new(); transport.process_input(&[], &mut spy).unwrap(); - assert!(transport.is_ready_for_encryption()); + assert!(transport.is_connected()); } #[test] From 31bef748fd14516465a9ea823756ce5b52dd6872 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 1 Sep 2020 14:11:42 -0700 Subject: [PATCH 73/96] refactor: Move drain_messages() behind Transport --- lightning/src/ln/peers/handler.rs | 60 ++----------------- lightning/src/ln/peers/transport.rs | 89 ++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 58 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 45148ad0cbc..09d83a7d7cb 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -14,7 +14,7 @@ use ln::msgs::{ChannelMessageHandler, LightningError, RoutingMessageHandler}; use ln::channelmanager::{SimpleArcChannelManager, SimpleRefChannelManager}; use util::ser::{Writeable}; use ln::wire; -use ln::wire::Encode; +use ln::wire::{Encode, Message}; use util::byte_utils; use util::events::{MessageSendEvent, MessageSendEventsProvider}; use util::logger::Logger; @@ -51,6 +51,9 @@ pub(super) trait ITransport { /// Returns true if the connection is established and encrypted messages can be sent. fn is_connected(&self) -> bool; + /// Returns all Messages that have been received and can be parsed by the Transport + fn drain_messages(&mut self, logger: L) -> Result, PeerHandleError> where L::Target: Logger; + /// Encodes, encrypts, and enqueues a message to the outbound queue. Panics if the connection is /// not established yet. fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q); @@ -571,60 +574,7 @@ impl PeerManager { } - Some(ref mut conduit) => { - // Using Iterators that can error requires special handling - // The item returned from next() has type Option, String>> - // The Some wrapper is stripped for each item inside the loop - // There are 3 valid match cases: - // 1) Some(Ok(Some(msg_data))) => Indicates a valid decrypted msg accessed via msg_data - // 2) Some(Err(_)) => Indicates an error during decryption that should be handled - // 3) None -> Indicates there were no messages available to decrypt - // Invalid Cases - // 1) Some(Ok(None)) => Translated to None case above so users of iterators can stop correctly - for msg_data_result in &mut conduit.decryptor { - match msg_data_result { - Ok(Some(msg_data)) => { - let mut reader = ::std::io::Cursor::new(&msg_data[..]); - let message_result = wire::read(&mut reader); - let message = match message_result { - Ok(x) => x, - Err(e) => { - match e { - msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(self.logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); - continue; - } - msgs::DecodeError::InvalidValue => { - log_debug!(self.logger, "Got an invalid value while deserializing message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ShortRead => { - log_debug!(self.logger, "Deserialization failed due to shortness of message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), - } - } - }; - - received_messages.push(message); - }, - Err(e) => { - log_trace!(self.logger, "Message decryption failed due to: {}", e); - return Err(PeerHandleError { no_connection_possible: false }); - } - Ok(None) => { - panic!("Invalid behavior. Conduit iterator should never return this match.") - } - } - } - } - } + let received_messages = peer.transport.drain_messages(&*self.logger)?; for message in received_messages { macro_rules! try_potential_handleerror { diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index d923d888cb7..32983ed8be5 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -3,12 +3,14 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::conduit::Conduit; -use ln::peers::handler::{ITransport, PayloadQueuer}; +use ln::peers::handler::{ITransport, PeerHandleError, PayloadQueuer}; use ln::peers::handshake::PeerHandshake; -use ln::wire; -use ln::wire::Encode; +use ln::{wire, msgs}; +use ln::wire::{Encode, Message}; use util::ser::{Writeable, VecWriter}; +use util::logger::Logger; +use std::ops::Deref; /// Interface used by Transport to interact with a handshake object pub trait IPeerHandshake { @@ -78,6 +80,68 @@ impl ITransport for Transport(&mut self, logger: L) -> Result, PeerHandleError> + where L::Target: Logger { + + let mut received_messages = vec![]; + + match self.conduit { + None => {} + Some(ref mut conduit) => { + // Using Iterators that can error requires special handling + // The item returned from next() has type Option, String>> + // The Some wrapper is stripped for each item inside the loop + // There are 3 valid match cases: + // 1) Some(Ok(Some(msg_data))) => Indicates a valid decrypted msg accessed via msg_data + // 2) Some(Err(_)) => Indicates an error during decryption that should be handled + // 3) None -> Indicates there were no messages available to decrypt + // Invalid Cases + // 1) Some(Ok(None)) => Translated to None case above so users of iterators can stop correctly + for msg_data_result in &mut conduit.decryptor { + match msg_data_result { + Ok(Some(msg_data)) => { + let mut reader = ::std::io::Cursor::new(&msg_data[..]); + let message_result = wire::read(&mut reader); + let message = match message_result { + Ok(x) => x, + Err(e) => { + match e { + msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::UnknownRequiredFeature => { + log_debug!(logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + continue; + } + msgs::DecodeError::InvalidValue => { + log_debug!(logger, "Got an invalid value while deserializing message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ShortRead => { + log_debug!(logger, "Deserialization failed due to shortness of message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), + } + } + }; + + received_messages.push(message); + }, + Err(e) => { + log_trace!(logger, "Message decryption failed due to: {}", e); + return Err(PeerHandleError { no_connection_possible: false }); + } + Ok(None) => { + panic!("Invalid behavior. Conduit iterator should never return this match.") + } + } + } + } + } + + Ok(received_messages) + } + fn is_connected(&self) -> bool { self.conduit.is_some() } @@ -102,6 +166,7 @@ mod tests { use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use ln::msgs; + use util::test_utils::TestLogger; fn create_outbound_for_test() -> Transport { let curve = secp256k1::Secp256k1::new(); @@ -254,4 +319,22 @@ mod tests { assert_matches!(&spy[..], [_]); } + + #[test] + fn inbound_not_connected_empty() { + let logger = TestLogger::new(); + let mut transport = create_inbound_for_test::(); + + let messages = transport.drain_messages(&logger).unwrap(); + assert_eq!(messages.len(), 0); + } + + #[test] + fn outbound_not_connected_empty() { + let logger = TestLogger::new(); + let mut transport = create_outbound_for_test::(); + + let messages = transport.drain_messages(&logger).unwrap(); + assert_eq!(messages.len(), 0); + } } \ No newline at end of file From 8904b231f569a1abe888f7c8b92f4495f4500dda Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sun, 30 Aug 2020 18:31:50 -0700 Subject: [PATCH 74/96] refactor: remove duplicate assert --- lightning/src/ln/peers/handler.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 09d83a7d7cb..9bceaa81001 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -410,7 +410,6 @@ impl PeerManager { { log_trace!(self.logger, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - assert!(peer.transport.is_connected()); peer.transport.enqueue_message($msg, &mut peer.pending_outbound_buffer) } } From f781569ccbbbf49d7c976f9ad89c0abbace375c2 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 1 Sep 2020 14:36:10 -0700 Subject: [PATCH 75/96] refactor: Move all enqueue logging to Transport --- lightning/src/ln/peers/handler.rs | 82 +++++++++++++---------------- lightning/src/ln/peers/transport.rs | 18 +++++-- 2 files changed, 49 insertions(+), 51 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 9bceaa81001..a4ec12cca1c 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -56,7 +56,7 @@ pub(super) trait ITransport { /// Encodes, encrypts, and enqueues a message to the outbound queue. Panics if the connection is /// not established yet. - fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q); + fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, logger: L) where L::Target: Logger; } @@ -406,15 +406,6 @@ impl PeerManager { - { - log_trace!(self.logger, "Encoding and sending sync update message of type {} to {}", $msg.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - peer.transport.enqueue_message($msg, &mut peer.pending_outbound_buffer) - } - } - } - while !peer.pending_outbound_buffer.is_blocked() { let queue_space = peer.pending_outbound_buffer.queue_space(); if queue_space > 0 { @@ -424,12 +415,12 @@ impl PeerManager PeerManager PeerManager PeerManager(&self, peers_needing_send: &mut HashSet, peer: &mut Peer, descriptor: Descriptor, message: &M) { - log_trace!(self.logger, "Enqueueing message of type {} to {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); - peer.transport.enqueue_message(message, &mut peer.pending_outbound_buffer); - peers_needing_send.insert(descriptor); + fn enqueue_message(&self, peers_needing_send: &mut HashSet, transport: &mut impl ITransport, output_buffer: &mut impl PayloadQueuer, descriptor: &Descriptor, message: &M) { + transport.enqueue_message(message, output_buffer, &*self.logger); + peers_needing_send.insert(descriptor.clone()); } fn do_read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8]) -> Result { @@ -564,7 +554,7 @@ impl PeerManager PeerManager { log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - self.enqueue_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), &msg); + self.enqueue_message(&mut peers.peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, peer_descriptor, &msg); continue; }, } @@ -675,7 +665,7 @@ impl PeerManager PeerManager { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; - self.enqueue_message(peers_needing_send, peer, peer_descriptor.clone(), &resp); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, &peer_descriptor, &resp); } }, wire::Message::Pong(_msg) => { @@ -856,7 +846,7 @@ impl PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager PeerManager ITransport for Transport(&mut self, message: &M, output_buffer: &mut Q) { + fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, logger: L) + where L::Target: Logger { + match self.conduit { None => panic!("Enqueueing messages only supported after transport is connected"), Some(ref mut conduit) => { + log_trace!(logger, "Enqueueing message of type {} to {}", message.type_id(), log_pubkey!(self.their_node_id.unwrap())); + let mut buffer = VecWriter(Vec::new()); wire::write(message, &mut buffer).unwrap(); output_buffer.push_back(conduit.encrypt(&buffer.0)); @@ -263,6 +267,7 @@ mod tests { #[test] #[should_panic(expected = "Enqueueing messages only supported after transport is connected")] fn inbound_enqueue_message_panic() { + let logger = TestLogger::new(); let mut transport = create_inbound_for_test::(); let mut spy = Vec::new(); @@ -270,13 +275,14 @@ mod tests { ponglen: 0, byteslen: 64, }; - transport.enqueue_message(&ping, &mut spy); + transport.enqueue_message(&ping, &mut spy, &logger); } // Test that enqueue_message() panics in the wrong state #[test] #[should_panic(expected = "Enqueueing messages only supported after transport is connected")] fn outbound_enqueue_message_panic() { + let logger = TestLogger::new(); let mut transport = create_outbound_for_test::(); let mut spy = Vec::new(); @@ -284,12 +290,13 @@ mod tests { ponglen: 0, byteslen: 64, }; - transport.enqueue_message(&ping, &mut spy); + transport.enqueue_message(&ping, &mut spy, &logger); } // Test that enqueue_message() puts something into the outbound buffer #[test] fn inbound_enqueue_message_encrypts() { + let logger = TestLogger::new(); let mut transport = create_inbound_for_test::(); let mut spy = Vec::new(); @@ -299,13 +306,14 @@ mod tests { ponglen: 0, byteslen: 64, }; - transport.enqueue_message(&ping, &mut spy); + transport.enqueue_message(&ping, &mut spy, &logger); assert_matches!(&spy[..], [_]); } #[test] fn outbound_enqueue_message_encrypts() { + let logger = TestLogger::new(); let mut transport = create_outbound_for_test::(); let mut spy = Vec::new(); @@ -315,7 +323,7 @@ mod tests { ponglen: 0, byteslen: 64, }; - transport.enqueue_message(&ping, &mut spy); + transport.enqueue_message(&ping, &mut spy, &logger); assert_matches!(&spy[..], [_]); } From 94721bdee7e2aec6513055ae1f45080a5307c774 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Fri, 4 Sep 2020 15:21:30 -0700 Subject: [PATCH 76/96] refactor: Make Transport the source of their_node_id This patch ontinues to separate state the exists before NOISE is complete and after it is complete to unlock future refactoring. Most callers immediately unwrapped the value from Peer and can just call Transport::get_their_node_id(). The duplicate connection disconnect path has been rewritten to determine whether or not to remove & send a disconnect event without needing to use a None value for Option All other users are in contexts where they either exit early or continue if !transport.is_connected() so it is also safe to call Transport::get_their_node_id() --- lightning/src/ln/peers/handler.rs | 101 +++++++++++++--------------- lightning/src/ln/peers/transport.rs | 44 +++++++++++- 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index a4ec12cca1c..dbc0d93cc04 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -51,6 +51,9 @@ pub(super) trait ITransport { /// Returns true if the connection is established and encrypted messages can be sent. fn is_connected(&self) -> bool; + /// Returns the node_id of the remote node. Panics if not connected. + fn get_their_node_id(&self) -> PublicKey; + /// Returns all Messages that have been received and can be parsed by the Transport fn drain_messages(&mut self, logger: L) -> Result, PeerHandleError> where L::Target: Logger; @@ -184,7 +187,6 @@ enum InitSyncTracker{ struct Peer { transport: Transport, outbound: bool, - their_node_id: Option, their_features: Option, pending_outbound_buffer: OutboundQueue, @@ -330,7 +332,7 @@ impl PeerManager PeerManager PeerManager PeerManager { if entry.get() != peer_descriptor { // Existing entry in map is from a different descriptor, this is a duplicate log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(&their_node_id)); - peer.their_node_id = None; return Err(PeerHandleError { no_connection_possible: false }); } else { // read_event for existing peer @@ -545,7 +544,6 @@ impl PeerManager { log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&their_node_id)); - peer.their_node_id = Some(their_node_id.clone()); if peer.outbound { let mut features = InitFeatures::known(); @@ -616,12 +614,12 @@ impl PeerManager, peer: &mut Peer, peer_descriptor: Descriptor, message: wire::Message) -> Result<(), MessageHandlingError> { - log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.their_node_id.unwrap())); + log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.transport.get_their_node_id())); // Need an Init as first message if let wire::Message::Init(_) = message { } else if peer.their_features.is_none() { - log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(peer.their_node_id.unwrap())); + log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(peer.transport.get_their_node_id())); return Err(PeerHandleError{ no_connection_possible: false }.into()); } @@ -654,13 +652,13 @@ impl PeerManager PeerManager { @@ -681,11 +679,11 @@ impl PeerManager PeerManager { - self.message_handler.chan_handler.handle_open_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + self.message_handler.chan_handler.handle_open_channel(&peer.transport.get_their_node_id(), peer.their_features.clone().unwrap(), &msg); }, wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&peer.their_node_id.unwrap(), peer.their_features.clone().unwrap(), &msg); + self.message_handler.chan_handler.handle_accept_channel(&peer.transport.get_their_node_id(), peer.their_features.clone().unwrap(), &msg); }, wire::Message::FundingCreated(msg) => { - self.message_handler.chan_handler.handle_funding_created(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_funding_created(&peer.transport.get_their_node_id(), &msg); }, wire::Message::FundingSigned(msg) => { - self.message_handler.chan_handler.handle_funding_signed(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_funding_signed(&peer.transport.get_their_node_id(), &msg); }, wire::Message::FundingLocked(msg) => { - self.message_handler.chan_handler.handle_funding_locked(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_funding_locked(&peer.transport.get_their_node_id(), &msg); }, wire::Message::Shutdown(msg) => { - self.message_handler.chan_handler.handle_shutdown(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_shutdown(&peer.transport.get_their_node_id(), &msg); }, wire::Message::ClosingSigned(msg) => { - self.message_handler.chan_handler.handle_closing_signed(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_closing_signed(&peer.transport.get_their_node_id(), &msg); }, // Commitment messages: wire::Message::UpdateAddHTLC(msg) => { - self.message_handler.chan_handler.handle_update_add_htlc(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_update_add_htlc(&peer.transport.get_their_node_id(), &msg); }, wire::Message::UpdateFulfillHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.transport.get_their_node_id(), &msg); }, wire::Message::UpdateFailHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_update_fail_htlc(&peer.transport.get_their_node_id(), &msg); }, wire::Message::UpdateFailMalformedHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.transport.get_their_node_id(), &msg); }, wire::Message::CommitmentSigned(msg) => { - self.message_handler.chan_handler.handle_commitment_signed(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_commitment_signed(&peer.transport.get_their_node_id(), &msg); }, wire::Message::RevokeAndACK(msg) => { - self.message_handler.chan_handler.handle_revoke_and_ack(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_revoke_and_ack(&peer.transport.get_their_node_id(), &msg); }, wire::Message::UpdateFee(msg) => { - self.message_handler.chan_handler.handle_update_fee(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_update_fee(&peer.transport.get_their_node_id(), &msg); }, wire::Message::ChannelReestablish(msg) => { - self.message_handler.chan_handler.handle_channel_reestablish(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_channel_reestablish(&peer.transport.get_their_node_id(), &msg); }, // Routing messages: wire::Message::AnnouncementSignatures(msg) => { - self.message_handler.chan_handler.handle_announcement_signatures(&peer.their_node_id.unwrap(), &msg); + self.message_handler.chan_handler.handle_announcement_signatures(&peer.transport.get_their_node_id(), &msg); }, wire::Message::ChannelAnnouncement(msg) => { let should_forward = match self.message_handler.route_handler.handle_channel_announcement(&msg) { @@ -1000,13 +998,10 @@ impl PeerManager continue, - Some(their_node_id) => { - if their_node_id == msg.contents.node_id_1 || their_node_id == msg.contents.node_id_2 { - continue - } - } + + let their_node_id = peer.transport.get_their_node_id(); + if their_node_id == msg.contents.node_id_1 || their_node_id == msg.contents.node_id_2 { + continue } if peer.transport.is_connected() { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); @@ -1119,12 +1114,17 @@ impl PeerManager panic!("Descriptor for disconnect_event is not already known to PeerManager"), Some(peer) => { - match peer.their_node_id { - Some(node_id) => { + if peer.transport.is_connected() { + let node_id = peer.transport.get_their_node_id(); + + if peers.node_id_to_descriptor.get(&node_id).unwrap() == descriptor { peers.node_id_to_descriptor.remove(&node_id); self.message_handler.chan_handler.peer_disconnected(&node_id, no_connection_possible); - }, - None => {} + } else { + // This must have been generated from a duplicate connection error + } + } else { + // Unconnected nodes never make it into node_id_to_descriptor } } }; @@ -1147,18 +1147,11 @@ impl PeerManager { - log_trace!(self.logger, "Disconnecting peer with id {} due to ping timeout", node_id); - node_id_to_descriptor.remove(&node_id); - self.message_handler.chan_handler.peer_disconnected(&node_id, false); - } - None => { - // This can't actually happen as we should have hit - // is_connected() previously on this same peer. - unreachable!(); - }, - } + let their_node_id = peer.transport.get_their_node_id(); + log_trace!(self.logger, "Disconnecting peer with id {} due to ping timeout", their_node_id); + node_id_to_descriptor.remove(&their_node_id); + self.message_handler.chan_handler.peer_disconnected(&their_node_id, false); + return false; } diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index fa23f712bdd..40362f9acad 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -31,7 +31,7 @@ pub trait IPeerHandshake { pub(super) struct Transport { pub(super) conduit: Option, handshake: PeerHandshakeImpl, - pub(super) their_node_id: Option, + their_node_id: Option, } impl ITransport for Transport { @@ -160,6 +160,11 @@ impl ITransport for Transport PublicKey { + assert!(self.is_connected(), "Retrieving the remote node_id is only supported after transport is connected"); + self.their_node_id.unwrap() + } } #[cfg(test)] @@ -254,6 +259,42 @@ mod tests { assert!(transport.is_connected()); } + // Test get_their_node_id() in unconnected and connected scenarios + #[test] + #[should_panic(expected = "Retrieving the remote node_id is only supported after transport is connected")] + fn inbound_unconnected_get_their_node_id_panics() { + let transport = create_inbound_for_test::(); + + let _should_panic = transport.get_their_node_id(); + } + + #[test] + #[should_panic(expected = "Retrieving the remote node_id is only supported after transport is connected")] + fn outbound_unconnected_get_their_node_id_panics() { + let mut transport = create_outbound_for_test::(); + transport.set_up_outbound(); + + let _should_panic = transport.get_their_node_id(); + } + + #[test] + fn inbound_unconnected_get_their_node_id() { + let mut transport = create_inbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + let _no_panic = transport.get_their_node_id(); + } + + #[test] + fn outbound_unconnected_get_their_node_id() { + let mut transport = create_inbound_for_test::(); + let mut spy = Vec::new(); + + transport.process_input(&[], &mut spy).unwrap(); + let _no_panic = transport.get_their_node_id(); + } + // Test that when a handshake completes is_connected() is correct #[test] fn outbound_handshake_complete_ready_for_encryption() { @@ -262,6 +303,7 @@ mod tests { transport.process_input(&[], &mut spy).unwrap(); assert!(transport.is_connected()); + let _no_panic = transport.get_their_node_id(); } #[test] From ada2a7f4b2b6c6fab07bd469226f727869c174fe Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Fri, 4 Sep 2020 15:28:23 -0700 Subject: [PATCH 77/96] tests: Add unit tests for PeerManager Use the newly abstracted Transport layer to write unit tests for most of the PeerManager functionality. This uses dependency inversion with the PeerManager to pass in a Transport test double that is configured to exercise the interesting code paths. To enable this, a new struct PeerManagerImpl has been created that has all of the original functionality of PeerManager, but includes a type parameter for the Transport implementation that should be used. To keep this test-feature hidden from public docs, the PeerManager struct is now just a shim that delegates all the calls to PeerManagerImpl. This provides a nice balance of a clean public interface with the features needed to create isolated tests. The tests make use of the Spy and Stub test patterns to control input state and validate the output state. --- lightning/src/ln/features.rs | 4 + lightning/src/ln/msgs.rs | 1 + lightning/src/ln/peers/handler.rs | 2038 ++++++++++++++++- lightning/src/ln/peers/mod.rs | 4 + lightning/src/ln/peers/test_message_macros.rs | 268 +++ lightning/src/ln/peers/test_util.rs | 166 +- lightning/src/ln/wire.rs | 2 +- lightning/src/util/test_utils.rs | 267 ++- 8 files changed, 2648 insertions(+), 102 deletions(-) create mode 100644 lightning/src/ln/peers/test_message_macros.rs diff --git a/lightning/src/ln/features.rs b/lightning/src/ln/features.rs index c4a15fad0c7..2fc8c4d486e 100644 --- a/lightning/src/ln/features.rs +++ b/lightning/src/ln/features.rs @@ -480,6 +480,10 @@ impl Features { pub(crate) fn requires_static_remote_key(&self) -> bool { ::requires_feature(&self.flags) } + #[cfg(test)] + pub(crate) fn clear_requires_static_remote_key(&mut self) { + ::clear_bits(&mut self.flags) + } } impl Features { diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 6936a7e93c4..25ce7c3b2c5 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -460,6 +460,7 @@ pub enum ErrorAction { } /// An Err type for failure to process messages. +#[derive(Clone)] pub struct LightningError { /// A human-readable message describing the error pub err: &'static str, diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index dbc0d93cc04..f6b316e3dc5 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -184,8 +184,8 @@ enum InitSyncTracker{ NodesSyncing(PublicKey), } -struct Peer { - transport: Transport, +struct Peer { + transport: TransportImpl, outbound: bool, their_features: Option, @@ -196,7 +196,7 @@ struct Peer { awaiting_pong: bool, } -impl Peer { +impl Peer { /// Returns true if the channel announcements/updates for the given channel should be /// forwarded to this peer. /// If we are sending our routing table to this peer and we have not yet sent channel @@ -221,8 +221,8 @@ impl Peer { } } -struct PeerHolder { - peers: HashMap, +struct PeerHolder { + peers: HashMap>, /// Added to by do_read_event for cases where we pushed a message onto the send buffer but /// didn't call do_attempt_write_data to avoid reentrancy. Cleared in process_events() peers_needing_send: HashSet, @@ -260,11 +260,23 @@ pub type SimpleRefPeerManager<'a, 'b, 'c, 'd, 'e, 'f, 'g, SD, M, T, F, C, L> = P /// SimpleArcPeerManager when you require a PeerManager with a static lifetime, such as when /// you're using lightning-net-tokio. pub struct PeerManager where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler, + L::Target: Logger { + inner: PeerManagerImpl, +} + +// Internal struct that mirrors the PeerManager interface, but can take in a Transport type parameter +// that is useful for testing. This enables the public docs for PeerManager to stay clean. +// +// All PeerManager calls just delegate to this struct directly and it is important to keep it that +// way to ensure full test coverage of the public APIs. +struct PeerManagerImpl where CM::Target: ChannelMessageHandler, RM::Target: RoutingMessageHandler, L::Target: Logger { message_handler: MessageHandler, - peers: Mutex>, + peers: Mutex>, our_node_secret: SecretKey, ephemeral_key_midstate: Sha256Engine, @@ -296,17 +308,122 @@ impl From for MessageHandlingError { /// Manages and reacts to connection events. You probably want to use file descriptors as PeerIds. /// PeerIds may repeat, but only after socket_disconnected() has been called. impl PeerManager where - CM::Target: ChannelMessageHandler, - RM::Target: RoutingMessageHandler, - L::Target: Logger { + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler, + L::Target: Logger { + /// Constructs a new PeerManager with the given message handlers and node_id secret key /// ephemeral_random_data is used to derive per-connection ephemeral keys and must be /// cryptographically secure random bytes. pub fn new(message_handler: MessageHandler, our_node_secret: SecretKey, ephemeral_random_data: &[u8; 32], logger: L) -> Self { + Self { + inner: PeerManagerImpl::new(message_handler, our_node_secret, ephemeral_random_data, logger) + } + } + + /// Get the list of node ids for peers which have completed the initial handshake. + /// + /// For outbound connections, this will be the same as the their_node_id parameter passed in to + /// new_outbound_connection, however entries will only appear once the initial handshake has + /// completed and we are sure the remote peer has the private key for the given node_id. + pub fn get_peer_node_ids(&self) -> Vec { + self.inner.get_peer_node_ids() + } + + /// Indicates a new outbound connection has been established to a node with the given node_id. + /// Note that if an Err is returned here you MUST NOT call socket_disconnected for the new + /// descriptor but must disconnect the connection immediately. + /// + /// Returns a small number of bytes to send to the remote node (currently always 50). + /// + /// Panics if descriptor is duplicative with some other descriptor which has not yet had a + /// socket_disconnected(). + pub fn new_outbound_connection(&self, their_node_id: PublicKey, descriptor: Descriptor) -> Result, PeerHandleError> { + self.inner.new_outbound_connection(their_node_id, descriptor) + } + + /// Indicates a new inbound connection has been established. + /// + /// May refuse the connection by returning an Err, but will never write bytes to the remote end + /// (outbound connector always speaks first). Note that if an Err is returned here you MUST NOT + /// call socket_disconnected for the new descriptor but must disconnect the connection + /// immediately. + /// + /// Panics if descriptor is duplicative with some other descriptor which has not yet had + /// socket_disconnected called. + pub fn new_inbound_connection(&self, descriptor: Descriptor) -> Result<(), PeerHandleError> { + self.inner.new_inbound_connection(descriptor) + } + + /// Indicates that there is room to write data to the given socket descriptor. + /// + /// May return an Err to indicate that the connection should be closed. + /// + /// Will most likely call send_data on the descriptor passed in (or the descriptor handed into + /// new_*\_connection) before returning. Thus, be very careful with reentrancy issues! The + /// invariants around calling write_buffer_space_avail in case a write did not fully complete + /// must still hold - be ready to call write_buffer_space_avail again if a write call generated + /// here isn't sufficient! Panics if the descriptor was not previously registered in a + /// new_\*_connection event. + pub fn write_buffer_space_avail(&self, descriptor: &mut Descriptor) -> Result<(), PeerHandleError> { + self.inner.write_buffer_space_avail(descriptor) + } + + /// Indicates that data was read from the given socket descriptor. + /// + /// May return an Err to indicate that the connection should be closed. + /// + /// Will *not* call back into send_data on any descriptors to avoid reentrancy complexity. + /// Thus, however, you almost certainly want to call process_events() after any read_event to + /// generate send_data calls to handle responses. + /// + /// If Ok(true) is returned, further read_events should not be triggered until a send_data call + /// on this file descriptor has resume_read set (preventing DoS issues in the send buffer). + /// + /// Panics if the descriptor was not previously registered in a new_*_connection event. + pub fn read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8]) -> Result { + self.inner.read_event(peer_descriptor, data) + } + + /// Checks for any events generated by our handlers and processes them. Includes sending most + /// response messages as well as messages generated by calls to handler functions directly (eg + /// functions like ChannelManager::process_pending_htlc_forward or send_payment). + pub fn process_events(&self) { + self.inner.process_events(); + } + + /// Indicates that the given socket descriptor's connection is now closed. + /// + /// This must only be called if the socket has been disconnected by the peer or your own + /// decision to disconnect it and must NOT be called in any case where other parts of this + /// library (eg PeerHandleError, explicit disconnect_socket calls) instruct you to disconnect + /// the peer. + /// + /// Panics if the descriptor was not previously registered in a successful new_*_connection event. + pub fn socket_disconnected(&self, descriptor: &Descriptor) { + self.inner.socket_disconnected(descriptor) + } + + /// This function should be called roughly once every 30 seconds. + /// It will send pings to each peer and disconnect those which did not respond to the last round of pings. + + /// Will most likely call send_data on all of the registered descriptors, thus, be very careful with reentrancy issues! + pub fn timer_tick_occured(&self) { + self.inner.timer_tick_occured() + } +} + + +impl PeerManagerImpl where + CM::Target: ChannelMessageHandler, + RM::Target: RoutingMessageHandler, + L::Target: Logger { + + fn new(message_handler: MessageHandler, our_node_secret: SecretKey, ephemeral_random_data: &[u8; 32], logger: L) -> Self { let mut ephemeral_key_midstate = Sha256::engine(); ephemeral_key_midstate.input(ephemeral_random_data); - PeerManager { + PeerManagerImpl { message_handler, peers: Mutex::new(PeerHolder { peers: HashMap::new(), @@ -321,12 +438,7 @@ impl PeerManager Vec { + fn get_peer_node_ids(&self) -> Vec { let peers = self.peers.lock().unwrap(); peers.peers.values().filter_map(|p| { if !p.transport.is_connected() || p.their_features.is_none() { @@ -349,20 +461,16 @@ impl PeerManager Result, PeerHandleError> { + fn new_outbound_connection(&self, their_node_id: PublicKey, descriptor: Descriptor) -> Result, PeerHandleError> { + let transport = TransportImpl::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); + self.new_outbound_connection_with_transport(descriptor, transport) + } + + fn new_outbound_connection_with_transport(&self, descriptor: Descriptor, mut transport: TransportImpl) -> Result, PeerHandleError> { let mut peers = self.peers.lock().unwrap(); - let mut transport = Transport::new_outbound(&self.our_node_secret, &their_node_id, &self.get_ephemeral_key()); let initial_bytes = transport.set_up_outbound(); - if peers.peers.insert(descriptor, Peer { + if peers.peers.insert(descriptor, Peer:: { transport, outbound: true, their_features: None, @@ -378,19 +486,15 @@ impl PeerManager Result<(), PeerHandleError> { + fn new_inbound_connection(&self, descriptor: Descriptor) -> Result<(), PeerHandleError> { + let transport = TransportImpl::new_inbound(&self.our_node_secret, &self.get_ephemeral_key()); + self.new_inbound_connection_with_transport(descriptor, transport) + } + + fn new_inbound_connection_with_transport(&self, descriptor: Descriptor, transport: TransportImpl) -> Result<(), PeerHandleError> { let mut peers = self.peers.lock().unwrap(); - if peers.peers.insert(descriptor, Peer { - transport: Transport::new_inbound(&self.our_node_secret, &self.get_ephemeral_key()), + if peers.peers.insert(descriptor, Peer:: { + transport, outbound: false, their_features: None, @@ -405,7 +509,7 @@ impl PeerManager) { while !peer.pending_outbound_buffer.is_blocked() { let queue_space = peer.pending_outbound_buffer.queue_space(); if queue_space > 0 { @@ -463,17 +567,7 @@ impl PeerManager Result<(), PeerHandleError> { + fn write_buffer_space_avail(&self, descriptor: &mut Descriptor) -> Result<(), PeerHandleError> { let mut peers = self.peers.lock().unwrap(); match peers.peers.get_mut(descriptor) { None => panic!("Descriptor for write_event is not already known to PeerManager"), @@ -485,19 +579,7 @@ impl PeerManager Result { + fn read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8]) -> Result { match self.do_read_event(peer_descriptor, data) { Ok(res) => Ok(res), Err(e) => { @@ -613,7 +695,7 @@ impl PeerManager, peer: &mut Peer, peer_descriptor: Descriptor, message: wire::Message) -> Result<(), MessageHandlingError> { + fn handle_message(&self, peers_needing_send: &mut HashSet, peer: &mut Peer, peer_descriptor: Descriptor, message: wire::Message) -> Result<(), MessageHandlingError> { log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.transport.get_their_node_id())); // Need an Init as first message @@ -799,10 +881,7 @@ impl PeerManager PeerManager PeerManager PeerManager {{ + let their_node_secret = SecretKey::from_slice(&[0x_12_u8; 32]).unwrap(); + PublicKey::from_secret_key(&Secp256k1::new(), &their_node_secret) + }} + } + + // Container to store the test double objects and test constants that are passed to the + // PeerManager and referenced in the validation code. It supports type parameters so tests can + // use a variety of message handler test doubles with a common set up path. + struct TestCtx { + chan_handler: CM, + logger: TestLogger, + random_data: [u8; 32], + route_handler: RM, + their_node_id: PublicKey, + } + + impl TestCtx { + + // Basic TestCtx with default ChannelMessageHandlerTestSpy and RoutingMessageHandlerTestStub + fn new() -> TestCtx { + TestCtx::::with_channel_and_routing_handlers( + ChannelMessageHandlerTestSpy::new(), RoutingMessageHandlerTestStub::new()) + } + + // TestCtx creation for tests that need to override both default handlers + fn with_channel_and_routing_handlers(chan_handler: CM, route_handler: RM) -> Self { + Self { + chan_handler, + logger: TestLogger::new(), + random_data: [0; 32], + route_handler, + their_node_id: test_ctx_their_node_id!() + } + } + + // TestCtx creation for tests that need to override the routing handler + fn with_routing_handler(route_handler: RM) -> TestCtx { + TestCtx::::with_channel_and_routing_handlers( + ChannelMessageHandlerTestSpy::new(), route_handler) + } + + // TestCtx creation for tests that need to override the message handler + fn with_channel_handler(channel_handler: CM) -> TestCtx { + TestCtx::::with_channel_and_routing_handlers( + channel_handler, RoutingMessageHandlerTestStub::new()) + } + } + + // Convenience macro to hide the RefCell/Builder noise when creating an unconnected transport to + // make the tests more readable. + macro_rules! new_unconnected_transport { + () => {{ + RefCell::new(TransportStubBuilder::new().finish()) + }} + } + + // Convenience macro to hide the RefCell/Builder noise when creating a connected transport to + // make the tests more readable. + macro_rules! new_connected_transport { + ($test_ctx:expr) => {{ + RefCell::new(TransportStubBuilder::new().set_connected(&$test_ctx.their_node_id).finish()) + }} + } + + // Convenience macro to hide the type parameters for the PeerManagerImpl instantiation and test + // context set up. Makes the tests more readable. + macro_rules! new_peer_manager_for_test { + ($test_ctx:expr) => {{ + let our_node_secret = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + let message_handler = MessageHandler { + chan_handler: &$test_ctx.chan_handler, + route_handler: &$test_ctx.route_handler, + }; + PeerManagerImpl::<_, _, _, _, &RefCell>::new(message_handler, our_node_secret, &$test_ctx.random_data, &$test_ctx.logger) + }} + } + + // Generates a PeerManager & TransportStub for test that has already connected and parsed + // the Init message. To reduce test expansion, this only tests with an outbound connection with + // the understanding that after the init process, both connections are identical. + macro_rules! new_peer_manager_post_init { + ($test_ctx: expr, $descriptor: expr, $transport: expr) => {{ + let mut features = InitFeatures::known(); + features.clear_initial_routing_sync(); + + $transport.borrow_mut().add_incoming_message(Message::Init(Init { features })); + + let peer_manager = new_peer_manager_for_test!(&$test_ctx); + new_outbound!(peer_manager, $descriptor, $transport); + assert_matches!(peer_manager.read_event($descriptor, &[]), Ok(_)); + + // Drain pre-init data from descriptor in recording + $descriptor.clear_recording(); + + peer_manager + }} + } + + // Convenience macro to make the tests more readable when creating an outbound connection + macro_rules! new_outbound { + ($peer_manager: expr, $descriptor: expr, $transport: expr) => {{ + $peer_manager.new_outbound_connection_with_transport($descriptor.clone(), $transport).unwrap() + }} + } + + // Convenience macro to make the tests more readable when creating an inbound connection + macro_rules! new_inbound { + ($peer_manager: expr, $descriptor: expr, $transport: expr) => {{ + $peer_manager.new_inbound_connection_with_transport($descriptor.clone(), $transport).unwrap() + }} + } + + // Convenience macro to execute read_event() and assert the return value + macro_rules! assert_read_event_errors { + ($peer_manager: expr, $descriptor: expr, $no_connection_possible: expr) => {{ + assert_matches!($peer_manager.read_event($descriptor, &[]), Err(PeerHandleError { no_connection_possible: $no_connection_possible })) + }} + } + + // Assert that a given slice matches a Message pattern. The TransportTestStub places items on + // the outbound queue unencrypted, so this is used to decode the unencrypted data that makes + // it through the SocketDescriptor. + macro_rules! assert_matches_message { + ($bytes: expr, $message_pattern: pat) => {{ + let mut reader = ::std::io::Cursor::new($bytes); + let message_result = wire::read(&mut reader); + let message = message_result.unwrap(); + assert_matches!(message, $message_pattern) + }} + } + + // Convenience macro for returning the spy value by function name + macro_rules! channel_handler_called { + ($test_ctx:expr, $fn_name: ident) => {{ + $test_ctx.chan_handler.called.lock().unwrap().$fn_name + }} + } + + // Convenience macro for returning the spy value by function name + macro_rules! route_handler_called { + ($test_ctx:expr, $fn_name: ident) => {{ + $test_ctx.route_handler.called.lock().unwrap().$fn_name + }} + } + + // ____ _ _____ _ _____ _ _ + // | _ \ ___ __ _ __| | | ____|_ _____ _ __ | |_ |_ _|__ ___| |_(_)_ __ __ _ + // | |_) / _ \/ _` |/ _` | | _| \ \ / / _ \ '_ \| __| | |/ _ \/ __| __| | '_ \ / _` | + // | _ < __/ (_| | (_| | | |___ \ V / __/ | | | |_ | | __/\__ \ |_| | | | | (_| | + // |_| \_\___|\__,_|\__,_| |_____| \_/ \___|_| |_|\__| |_|\___||___/\__|_|_| |_|\__, | + // |___/ + + // Test that a new inbound connection: + // * get_peer_node_ids() does not contain the node_id + #[test] + fn new_inbound_not_in_get_peer_node_ids() { + let test_ctx = TestCtx::::new(); + let descriptor = SocketDescriptorMock::new(); + let mut transport = new_unconnected_transport!(); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + + new_inbound!(peer_manager, descriptor, &mut transport); + + assert!(peer_manager.get_peer_node_ids().is_empty()); + } + + // Test that a new outbound connection: + // * get_peer_node_ids() does not contain the node_id + #[test] + fn new_outbound_not_in_get_peer_node_ids() { + let test_ctx = TestCtx::::new(); + let descriptor = SocketDescriptorMock::new(); + let mut transport = new_unconnected_transport!(); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + + new_outbound!(peer_manager, descriptor, &mut transport); + + assert!(peer_manager.get_peer_node_ids().is_empty()); + } + + // Test that a new inbound connection: + // * read_event() returns errors from the Transport code + #[test] + fn new_inbound_transport_error_returns_error() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = + RefCell::new(TransportStubBuilder::new().process_returns_error().finish()); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + + new_inbound!(peer_manager, descriptor, &mut transport); + + assert_read_event_errors!(peer_manager, &mut descriptor, false); + } + + // Test that a new outbound connection: + // * read_event() returns errors from the Transport code + #[test] + fn new_outbound_transport_error_returns_error() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = + RefCell::new(TransportStubBuilder::new().process_returns_error().finish()); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + + new_outbound!(peer_manager, descriptor, &mut transport); + + assert_read_event_errors!(peer_manager, &mut descriptor, false); + } + + // Test that an inbound connection with a connected Transport, but no Init message + // * get_peer_node_ids() does not contain the node_id + // * process_events() does not send an Init message (must receive from Initiator first) + #[test] + fn inbound_connected_transport_not_in_get_peer_node_ids() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + + new_inbound!(peer_manager, descriptor, &mut transport); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + + assert!(peer_manager.get_peer_node_ids().is_empty()); + peer_manager.process_events(); + descriptor.assert_called_with(vec![]); + } + + // Test that an outbound connection with a connected Transport, but no Init message + // * read_event() does not call peer_disconnected callback if an error is returned from Transport + // XXXBUG: peer_connected is called after the Init message, but peer_disconnected is called + // with any error after the NOISE handshake is complete + #[test] + fn outbound_connected_transport_error_does_not_call_peer_disconnected_on_error() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + new_outbound!(peer_manager, descriptor, &transport); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + + // Signal the error in transport and ensure we don't send a dangling peer_disconnected + transport.borrow_mut().process_returns_error(); + assert_read_event_errors!(peer_manager, &mut descriptor, false); + assert!(!channel_handler_called!(&test_ctx, peer_connected)); + // assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that an inbound connection with a connected Transport and queued Init message: + // * XXXBUG: does not send anything in read_event() + // * read_event() calls the peer_connected channel manager callback + // * process_events() sends an Init message + #[test] + fn inbound_connected_transport_responds_with_init() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + transport.borrow_mut().add_incoming_message( + Message::Init(Init { features: InitFeatures::known() })); + + new_inbound!(peer_manager, descriptor, &mut transport); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + assert!(channel_handler_called!(&test_ctx, peer_connected)); + // descriptor.assert_called_with(vec![]); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Init(_)); + } + + // Test that an inbound connection with a connected Transport and queued Init message: + // * read_event() returns true if the outbound queue is full + // * read_event() returns false once room is made and write_buffer_space_avail is called + // Test leverages a 0 capacity SocketDescriptor and the initial routing sync from + // TestRoutingMessagehandler to fill the queue + #[test] + fn inbound_connected_transport_full_outbound_queue() { + let routing_handler = TestRoutingMessageHandler::new(); + let test_ctx = TestCtx::::with_routing_handler(routing_handler); + let mut descriptor = SocketDescriptorMock::with_fixed_size(0); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + transport.borrow_mut().add_incoming_message(Message::Init(Init { features: InitFeatures::known() })); + + new_inbound!(peer_manager, descriptor, &mut transport); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(true)); + + // Call w/o write_buffer_space_avail still returns Ok(true) + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(true)); + + // Call w/o more room in SocketDescriptor still returns Ok(true) + peer_manager.write_buffer_space_avail(&mut descriptor).unwrap(); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(true)); + + // Call after more room in SocketDescriptor returns Ok(false) + descriptor.make_room(100000); + peer_manager.write_buffer_space_avail(&mut descriptor).unwrap(); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Init(_)); + assert!(channel_handler_called!(&test_ctx, peer_connected)); + } + + // Test that an outbound connection with a connected Transport: + // * get_peer_node_ids() does not contain the node_id + // * XXXBUG: does not send anything in read_event() + // * process_events() sends an Init message + #[test] + fn outbound_connected_transport_sends_init_in_process_events() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + + new_outbound!(peer_manager, descriptor, &mut transport); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + // XXXBUG: Should not call back into descriptor + // descriptor.assert_called_with(vec![]); + + assert!(peer_manager.get_peer_node_ids().is_empty()); + + peer_manager.process_events(); + let recording = descriptor.get_recording(); + assert_eq!(1, recording.len()); + + assert_matches_message!(&recording[0].0, Message::Init(_)); + } + + // Test that an outbound connection with a connected Transport: + // * read_event() errors when receiving a Non-Init message first + // * read_event() calls the peer_disconnected channel manager callback + #[test] + fn inbound_connected_transport_non_init_first_fails() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + transport.borrow_mut().add_incoming_message(Message::Ping(Ping { ponglen: 0, byteslen: 0 })); + + new_inbound!(peer_manager, descriptor, &mut transport); + assert_read_event_errors!(peer_manager, &mut descriptor, false); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that an outbound connection with a connected Transport: + // * read_event() errors when receiving a Non-Init message first + // * read_event() calls the peer_disconnected channel manager callback + #[test] + fn outbound_connected_transport_non_init_first_fails() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + transport.borrow_mut().add_incoming_message(Message::Ping(Ping { ponglen: 0, byteslen: 0 })); + + new_outbound!(peer_manager, descriptor, &mut transport); + assert_read_event_errors!(peer_manager, &mut descriptor, false); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that an inbound connection with a connected Transport: + // * read_event() errors out with no_connection_possible if an Init message contains requires_unknown_bits + // * read_event() calls the peer_disconnected channel manager callback + #[test] + fn inbound_connected_transport_init_with_required_unknown_first_fails() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + let mut features = InitFeatures::known(); + features.set_required_unknown_bits(); + transport.borrow_mut().add_incoming_message(Message::Init(Init { features })); + + new_inbound!(peer_manager, descriptor, &mut transport); + assert_read_event_errors!(peer_manager, &mut descriptor, true); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that an outbound connection with a connected Transport: + // * read_event() errors out with no_connection_possible if an Init message contains requires_unknown_bits + // * read_event() calls the peer_disconnected channel manager callback + #[test] + fn outbound_connected_transport_init_with_required_unknown_first_fails() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + let mut features = InitFeatures::known(); + features.set_required_unknown_bits(); + transport.borrow_mut().add_incoming_message(Message::Init(Init { features })); + + new_outbound!(peer_manager, descriptor, &mut transport); + assert_read_event_errors!(peer_manager, &mut descriptor, true); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that an inbound connection with a connected Transport: + // * read_event() errors out with no_connection_possible if an Init message does not contain requires_static_remote_key + // * read_event() calls the peer_disconnected channel manager callback + #[test] + fn inbound_connected_transport_init_with_clear_requires_static_remote_key() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + let mut features = InitFeatures::known(); + features.clear_requires_static_remote_key(); + transport.borrow_mut().add_incoming_message(Message::Init(Init { features })); + + new_inbound!(peer_manager, descriptor, &mut transport); + assert_read_event_errors!(peer_manager, &mut descriptor, true); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that an outbound connection with a connected Transport: + // * read_event() errors out with no_connection_possible if an Init message does not contain requires_static_remote_key + // * read_event() calls the peer_disconnected channel manager callback + #[test] + fn outbound_connected_transport_init_with_clear_requires_static_remote_key() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + let mut features = InitFeatures::known(); + features.clear_requires_static_remote_key(); + transport.borrow_mut().add_incoming_message(Message::Init(Init { features })); + + new_outbound!(peer_manager, descriptor, &mut transport); + assert_read_event_errors!(peer_manager, &mut descriptor, true); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that an inbound connection with a connected Transport and queued Init Message: + // * read_event() calls the peer_connected channel manager callback + // * get_peer_node_ids() contains the node_id + #[test] + fn inbound_connected_transport_after_init_in_get_peer_node_ids() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + transport.borrow_mut().add_incoming_message(Message::Init(Init { features: InitFeatures::known() })); + + new_inbound!(peer_manager, descriptor, &mut transport); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + + assert!(peer_manager.get_peer_node_ids().contains(&test_ctx.their_node_id)); + assert!(channel_handler_called!(&test_ctx, peer_connected)); + } + + // Test that an outbound connection with a connected Transport and queued Init Message: + // * read_event() calls the peer_connected channel manager callback + // * get_peer_node_ids() contains the node_id + #[test] + fn outbound_connected_transport_after_init_in_get_peer_node_ids() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + transport.borrow_mut().add_incoming_message(Message::Init(Init { features: InitFeatures::known() })); + + new_outbound!(peer_manager, descriptor, &mut transport); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + + assert!(peer_manager.get_peer_node_ids().contains(&test_ctx.their_node_id)); + assert!(channel_handler_called!(&test_ctx, peer_connected)); + } + + // Test that a post-Init connection: + // * read_event() propagates an error coming out of Transport + // * read_event() calls the peer_disconnected channel manager callback + // * get_peer_node_ids() does not contain the node_id + #[test] + fn post_init_connected_after_error_not_in_get_peer_node_ids() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + // Set transport to return an error + transport.borrow_mut().process_returns_error(); + + // Verify errors out and removed from get_peer_node_ids() + assert_read_event_errors!(peer_manager, &mut descriptor, false); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(peer_manager.get_peer_node_ids().is_empty()); + } + + // Test that a post-Init duplicate connection: + // * read_event() returns an error + // * get_peer_node_ids() contains the original node_id + #[test] + fn post_init_duplicate_connection_errors_and_original_keeps_existing() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + // Create a duplicate connection from the same node_id + let mut duplicate_connection_descriptor = SocketDescriptorMock::new(); + let mut duplicate_connection_transport = RefCell::new(TransportStubBuilder::new() + .set_connected(&test_ctx.their_node_id) + .finish()); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + assert!(peer_manager.get_peer_node_ids().contains(&test_ctx.their_node_id)); + + // Duplicate connection errors out + new_outbound!(peer_manager, duplicate_connection_descriptor, &mut duplicate_connection_transport); + assert_read_event_errors!(peer_manager, &mut duplicate_connection_descriptor, false); + + // And any queued messages such as an outgoing Init are never sent + peer_manager.process_events(); + duplicate_connection_descriptor.assert_called_with(vec![]); + + // But the original still exists in get_peer_node_ids() + assert!(peer_manager.get_peer_node_ids().contains(&test_ctx.their_node_id)); + } + + // __ __ _____ _ _ + // | \/ | ___ ___ ___ __ _ __ _ ___ |_ _|__ ___| |_(_)_ __ __ _ + // | |\/| |/ _ \/ __/ __|/ _` |/ _` |/ _ \ | |/ _ \/ __| __| | '_ \ / _` | + // | | | | __/\__ \__ \ (_| | (_| | __/ | | __/\__ \ |_| | | | | (_| | + // |_| |_|\___||___/___/\__,_|\__, |\___| |_|\___||___/\__|_|_| |_|\__, | + // |___/ |___/ + + // Test that a post-Init connection: + // * read_event() returns an error if it receives a second Init message + // * read_event() calls the peer_disconnected channel manager callback + #[test] + fn post_init_second_init_fails() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Init(Init { features: InitFeatures::known() })); + + assert_read_event_errors!(peer_manager, &mut descriptor, false); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } + + // Test that a post-Init connection: + // * read_event() does not propagate an Error Message with no printable + // * read_event() calls the handle_error channel manager callback + #[test] + fn post_init_error_message_without_printable() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Error(ErrorMessage { channel_id: [1; 32], data: "".to_string() })); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + assert!(channel_handler_called!(&test_ctx, handle_error)); + } + + // Test that a post-Init connection: + // * read_event() does not propagate an Error Message with printable + // * read_event() calls the handle_error channel manager callback + #[test] + fn post_init_error_message_with_printable() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Error(ErrorMessage { channel_id: [1; 32], data: "error".to_string() })); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + assert!(channel_handler_called!(&test_ctx, handle_error)); + } + + // Test that a post-Init connection: + // * read_event() does not propagate an Error Message with a control character + // * read_event() calls the handle_error channel manager callback + #[test] + fn post_init_error_message_with_non_ascii_ignored() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Error(ErrorMessage { channel_id: [1; 32], data: "\x00".to_string() })); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + assert!(channel_handler_called!(&test_ctx, handle_error)); + } + + // Test that a post-Init connection: + // * read_event() returns an error when it receives an Error Message with a 0 channel_id + // * read_event() calls the handle_error channel manager callback + #[test] + fn post_init_error_message_with_zero_channel_id() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Error(ErrorMessage { channel_id: [0; 32], data: "".to_string() })); + + assert_read_event_errors!(peer_manager, &mut descriptor, true); + assert!(channel_handler_called!(&test_ctx, handle_error)); + } + + // Test that a post-Init connection: + // * read_event() returns an error when it receives Message::Unknown (even) + #[test] + fn post_init_unknown_message_even() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Unknown(wire::MessageType(254))); + + assert_read_event_errors!(peer_manager, &mut descriptor, true); + } + + // Test that a post-Init connection: + // * read_event() ignores Message::Unknown (odd) + #[test] + fn post_init_unknown_message_odd() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Unknown(wire::MessageType(255))); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + } + + // Test that a post-init connection: + // * read_event() calls the correct ChannelMessageHandler callback given the correct message type + macro_rules! generate_handle_message_test { + ($expected_cb: ident, $msg: expr) => { + #[test] + fn $expected_cb() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + transport.borrow_mut().add_incoming_message($msg); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + assert!(channel_handler_called!(&test_ctx, $expected_cb)); + } + } + } + + generate_handle_message_test!(handle_open_channel, Message::OpenChannel(fake_open_channel_msg!())); + generate_handle_message_test!(handle_accept_channel, Message::AcceptChannel(fake_accept_channel_msg!())); + generate_handle_message_test!(handle_funding_created, Message::FundingCreated(fake_funding_created_msg!())); + generate_handle_message_test!(handle_funding_signed, Message::FundingSigned(fake_funding_signed_msg!())); + generate_handle_message_test!(handle_funding_locked, Message::FundingLocked(fake_funding_locked_msg!())); + generate_handle_message_test!(handle_shutdown, Message::Shutdown(fake_shutdown_msg!())); + generate_handle_message_test!(handle_closing_signed, Message::ClosingSigned(fake_closing_signed_msg!())); + generate_handle_message_test!(handle_update_add_htlc, Message::UpdateAddHTLC(fake_update_add_htlc_msg!())); + generate_handle_message_test!(handle_update_fulfill_htlc, Message::UpdateFulfillHTLC(fake_update_fulfill_htlc_msg!())); + generate_handle_message_test!(handle_update_fail_htlc, Message::UpdateFailHTLC(fake_update_fail_htlc_msg!())); + generate_handle_message_test!(handle_update_fail_malformed_htlc, Message::UpdateFailMalformedHTLC(fake_update_fail_malformed_htlc_msg!())); + generate_handle_message_test!(handle_commitment_signed, Message::CommitmentSigned(fake_commitment_signed_msg!())); + generate_handle_message_test!(handle_revoke_and_ack, Message::RevokeAndACK(fake_revoke_and_ack_msg!())); + generate_handle_message_test!(handle_update_fee, Message::UpdateFee(fake_update_fee_msg!())); + generate_handle_message_test!(handle_channel_reestablish, Message::ChannelReestablish(fake_channel_reestablish_msg!())); + generate_handle_message_test!(handle_announcement_signatures, Message::AnnouncementSignatures(fake_announcement_signatures_msg!())); + + // Test that a post-Init connection: + // * read_event() returns an error if a ChannelAnnouncement message is received and the routing handler + // returns ErrorAction::DisconnectPeer + // * read_event() calls the peer_disconnected channel manager callback + // * read_event() does not call disconnect_socket() is not called on the SocketDescriptor + #[test] + fn post_init_handle_channel_announcement_disconnect_peer() { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_announcement_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::DisconnectPeer { msg: None } }); + let test_ctx = TestCtx::::with_routing_handler(routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()))); + + assert_read_event_errors!(peer_manager, &mut descriptor, false); + assert!(peer_manager.get_peer_node_ids().is_empty()); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!descriptor.disconnect_called()); + } + + // Test generator macro to reduce duplication across the broadcast message cases. + // (test name, expression that returns a routing handler, message that will be queued, closure taking (peer_manager, descriptor) that does the validation) + macro_rules! generate_broadcast_message_test { + ($test_name: ident, $routing_handler: expr, $message: expr, $validation: tt) => { + #[test] + fn $test_name() { + let test_ctx = TestCtx::::with_routing_handler($routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message($message); + + $validation(peer_manager, descriptor) + } + } + } + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelAnnouncement message is received and the routing handler + // returns ErrorAction::IgnoreError + generate_broadcast_message_test!(post_init_handle_channel_announcement_ignore_error, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_announcement_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }); + routing_handler + }, + Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), + (| peer_manager: PeerManagerImpl>, mut descriptor | + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)) + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelAnnouncement message is received and the routing handler + // returns ErrorAction::IgnoreError + // * process_events() sends an ErrorMessage + generate_broadcast_message_test!(post_init_handle_channel_announcement_send_error_message, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_announcement_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::SendErrorMessage { msg: ErrorMessage { channel_id: [0; 32], data: "".to_string() } } }); + routing_handler + }, + Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Error(_)) + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelAnnouncement message is received and the routing handler + // returns true + generate_broadcast_message_test!(post_init_handle_channel_announcement_should_forward, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_announcement_return = Ok(true); + routing_handler + }, + Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelAnnouncement message is received and the routing handler + // returns false + generate_broadcast_message_test!(post_init_handle_channel_announcement_should_not_forward, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_announcement_return = Ok(false); + routing_handler + }, + Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a NodeAnnouncement message is received and the routing handler + // returns ErrorAction::IgnoreError + generate_broadcast_message_test!(post_init_handle_node_announcement_ignore_error, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_node_announcement_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }); + routing_handler + }, + Message::NodeAnnouncement(fake_node_announcement_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)) + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a NodeAnnouncement message is received and the routing handler + // returns ErrorAction::IgnoreError + // * process_events() sends an ErrorMessage + generate_broadcast_message_test!(post_init_handle_node_announcement_send_error_message, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_node_announcement_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::SendErrorMessage { msg: ErrorMessage { channel_id: [0; 32], data: "".to_string() } } }); + routing_handler + }, + Message::NodeAnnouncement(fake_node_announcement_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Error(_)) + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a NodeAnnouncement message is received and the routing handler + // returns true + generate_broadcast_message_test!(post_init_handle_node_announcement_should_forward, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_node_announcement_return = Ok(true); + routing_handler + }, + Message::NodeAnnouncement(fake_node_announcement_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a NodeAnnouncement message is received and the routing handler + // returns false + generate_broadcast_message_test!(post_init_handle_node_announcement_should_not_forward, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_node_announcement_return = Ok(false); + routing_handler + }, + Message::NodeAnnouncement(fake_node_announcement_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelUpdate message is received and the routing handler + // returns ErrorAction::IgnoreError + generate_broadcast_message_test!(post_init_handle_channel_update_ignore_error, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }); + routing_handler + }, + Message::ChannelUpdate(fake_channel_update_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)) + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelUpdate message is received and the routing handler + // returns ErrorAction::IgnoreError + // * process_events() sends an ErrorMessage + generate_broadcast_message_test!(post_init_handle_channel_update_send_error_message, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::SendErrorMessage { msg: ErrorMessage { channel_id: [0; 32], data: "".to_string() } } }); + routing_handler + }, + Message::ChannelUpdate(fake_channel_update_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Error(_)) + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelUpdate message is received and the routing handler + // returns true + generate_broadcast_message_test!(post_init_handle_channel_update_should_forward, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Ok(true); + routing_handler + }, + Message::ChannelUpdate(fake_channel_update_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + } + )); + + // Test that a post-Init connection: + // * read_event() returns Ok(_) if a ChannelUpdate message is received and the routing handler + // returns false + generate_broadcast_message_test!(post_init_handle_channel_update_should_not_forward, { + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Ok(false); + routing_handler + }, + Message::ChannelUpdate(fake_channel_update_msg!()), + (| peer_manager: PeerManagerImpl>, mut descriptor | { + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + } + )); + + // _____ _ _____ _ _ + // | ____|_ _____ _ __ | |_ |_ _|__ ___| |_(_)_ __ __ _ + // | _| \ \ / / _ \ '_ \| __| | |/ _ \/ __| __| | '_ \ / _` | + // | |___ \ V / __/ | | | |_ | | __/\__ \ |_| | | | | (_| | + // |_____| \_/ \___|_| |_|\__| |_|\___||___/\__|_|_| |_|\__, | + // |___/ + + // To reduce test expansion, the unknown, unconnected, and connected variants are only run + // on one event type. All handlers use the same accessor to retrieve the connected node so one + // test of those paths should be sufficient. The initialized variant is run on all types which + // is where the interesting code is run. Once features are added to take action on unconnected + // nodes, this should be revisited. + + // Test that a post-Init connection: + // * process_events() does not send an OpenChannel message when it receives a SendOpenChannel + // event if the peer is unknown + #[test] + fn unknown_node_send_open_channel_event() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(MessageSendEvent::SendOpenChannel { + node_id: fake_public_key!(), + msg: fake_open_channel_msg!() + }); + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() does not send an OpenChannel message when it receives a SendOpenChannel + // event if the peer is known, but the NOISE handshake is not complete + #[test] + fn unconnected_transport_send_open_channel_event() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(MessageSendEvent::SendOpenChannel { + node_id: fake_public_key!(), + msg: fake_open_channel_msg!() + }); + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let descriptor = SocketDescriptorMock::new(); + let mut transport = new_unconnected_transport!(); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + new_outbound!(peer_manager, descriptor, &mut transport); + + peer_manager.process_events(); + + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() does not send an OpenChannel message when it receives a SendOpenChannel + // event if the peer is known, but the Init message has not been received + #[test] + fn connected_transport_send_open_channel_event() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(MessageSendEvent::SendOpenChannel { + node_id: fake_public_key!(), + msg: fake_open_channel_msg!() + }); + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let descriptor = SocketDescriptorMock::new(); + let mut transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + new_outbound!(peer_manager, descriptor, &mut transport); + + peer_manager.process_events(); + + assert!(descriptor.get_recording().is_empty()); + } + + // Test generator macro to reduce duplication across the event handlers that just enqueue a message + // (test name, event to send, expected sent message) + macro_rules! generate_event_handler_test { + ($test_name: ident, $event: expr, $expected_message: pat) => { + #[test] + fn $test_name() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push($event); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, $expected_message); + } + } + } + + // Test that a post-Init connection: + // * process_events() sends an OpenChannel message when it receives a SendOpenChannel event for + // an initialized node + generate_event_handler_test!(post_init_send_open_channel, + SendOpenChannel { + node_id: test_ctx_their_node_id!(), + msg: fake_open_channel_msg!(), + }, + Message::OpenChannel(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an AcceptChannel message when it receives a SendAcceptChannel event + // for an initialized node + generate_event_handler_test!(post_init_send_accept_channel, + SendAcceptChannel { + node_id: test_ctx_their_node_id!(), + msg: fake_accept_channel_msg!(), + }, + Message::AcceptChannel(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an AcceptChannel message when it receives a SendAcceptChannel event + // for an initialized node + generate_event_handler_test!(post_init_send_funding_created, + SendFundingCreated { + node_id: test_ctx_their_node_id!(), + msg: fake_funding_created_msg!(), + }, + Message::FundingCreated(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an FundingSigned message when it receives a SendFundingSigned event + // for an initialized node + generate_event_handler_test!(post_init_send_funding_signed, + SendFundingSigned { + node_id: test_ctx_their_node_id!(), + msg: fake_funding_signed_msg!(), + }, + Message::FundingSigned(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an FundingLocked message when it receives a SendFundingLocked event + // for an initialized node + generate_event_handler_test!(post_init_send_funding_locked, + SendFundingLocked { + node_id: test_ctx_their_node_id!(), + msg: fake_funding_locked_msg!(), + }, + Message::FundingLocked(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an AnnouncementSignatures message when it receives a + // SendAnnouncementSignatures event for an initialized node + generate_event_handler_test!(post_init_send_announcement_signatures, + SendAnnouncementSignatures { + node_id: test_ctx_their_node_id!(), + msg: fake_announcement_signatures_msg!(), + }, + Message::AnnouncementSignatures(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an RevokeAndACK message when it receives a SendRevokeAndACK event + // for an initialized node + generate_event_handler_test!(post_init_send_revoke_ack, + SendRevokeAndACK { + node_id: test_ctx_their_node_id!(), + msg: fake_revoke_and_ack_msg!(), + }, + Message::RevokeAndACK(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an ClosingSigned message when it receives a SendClosingSigned event + // for an initialized node + generate_event_handler_test!(post_init_send_closing_signed, + SendClosingSigned { + node_id: test_ctx_their_node_id!(), + msg: fake_closing_signed_msg!(), + }, + Message::ClosingSigned(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an Shutdown message when it receives a Shutdown event for an + // initialized node + generate_event_handler_test!(post_init_send_shutdown, + SendShutdown { + node_id: test_ctx_their_node_id!(), + msg: fake_shutdown_msg!(), + }, + Message::Shutdown(_) + ); + + // Test that a post-Init connection: + // * process_events() sends an ChannelReestablish message when it receives a + // SendChannelReestablish event for an initialized node + generate_event_handler_test!(post_init_send_channel_reestablish, + SendChannelReestablish { + node_id: test_ctx_their_node_id!(), + msg: fake_channel_reestablish_msg!() + }, + Message::ChannelReestablish(_) + ); + + // Test that a post-Init connection: + // * process_events() sends relevant HTLC messages when it receives a UpdateHTLC event for an + // initialized node + #[test] + fn post_init_send_update_htlcs() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(UpdateHTLCs { + node_id: test_ctx_their_node_id!(), + updates: CommitmentUpdate { + update_add_htlcs: vec![fake_update_add_htlc_msg!()], + update_fulfill_htlcs: vec![fake_update_fulfill_htlc_msg!()], + update_fail_htlcs: vec![fake_update_fail_htlc_msg!()], + update_fail_malformed_htlcs: vec![fake_update_fail_malformed_htlc_msg!()], + update_fee: Some(fake_update_fee_msg!()), + commitment_signed: fake_commitment_signed_msg!() + } + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::UpdateAddHTLC(_)); + assert_matches_message!(&recording[1].0, Message::UpdateFulfillHTLC(_)); + assert_matches_message!(&recording[2].0, Message::UpdateFailHTLC(_)); + assert_matches_message!(&recording[3].0, Message::UpdateFailMalformedHTLC(_)); + assert_matches_message!(&recording[4].0, Message::UpdateFee(_)); + assert_matches_message!(&recording[5].0, Message::CommitmentSigned(_)); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the + // route_handler.handle_channel_announcement errors + #[test] + fn post_init_broadcast_channel_announcement_route_handler_handle_announcement_errors() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_announcement_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the + // route_handler.handle_channel_update errors + #[test] + fn post_init_broadcast_channel_announcement_route_handler_handle_update_errors() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the + // route_handler.handle_channel_announcement returns false + // XXXBUG: Implementation does not check return value of handle_channel_announcement, only that it didn't error + #[test] + fn post_init_broadcast_channel_announcement_route_handler_handle_announcement_returns_false() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_announcement_return = Ok(false); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + // assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the + // route_handler.handle_channel_update returns false + // XXXBUG: Implementation does not check return value of handle_channel_update, only that it didn't error + #[test] + fn post_init_broadcast_channel_announcement_route_handle_update_returns_false() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Ok(false); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + // assert!(descriptor.get_recording().is_empty()); + } + + // To reduce test expansion, the unconnected and connected transport tests are only run on one + // broadcast variant. All broadcast implementations use the same API to determine whether or not + // the peer wants the announcement forwarded. + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the peer + // has not completed the NOISE handshake + #[test] + fn unconnected_transport_broadcast_channel_announcement() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Ok(false); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_unconnected_transport!(); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + new_outbound!(peer_manager, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the peer + // has not received an Init message + #[test] + fn connected_transport_broadcast_channel_announcement() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Ok(false); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + new_outbound!(peer_manager, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the peer + // is initialized, but Peer::should_forward_channel_announcement returns false + #[test] + fn connected_transport_broadcast_channel_announcement_short_channel_id_larger_than_current_sync() { + let channel_handler = TestChannelMessageHandler::new(); + let routing_handler = RoutingMessageHandlerTestStub::new(); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(10000, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_for_test!(&test_ctx); + new_outbound!(peer_manager, &mut descriptor, &transport); + + // Use an Init sequence with initial_routing_sync and use an arbitrarily high short + // channel_id in the fake_channel_announcement_msg to create the state. This test knows a bit too + // much and future refactoring can make this much better. + transport.borrow_mut().add_incoming_message(Message::Init(Init { features: InitFeatures::known() })); + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the peer + // is node_id_1 + #[test] + fn post_init_broadcast_channel_announcement_skip_node_id_1() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, test_ctx_their_node_id!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the peer + // is node_id_2 + #[test] + fn post_init_broadcast_channel_announcement_skip_node_id_2() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), test_ctx_their_node_id!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends the relevant messages when it receives a BroadcastChannelAnnouncement + #[test] + fn post_init_broadcast_channel_announcement() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { + msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), + update_msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::ChannelAnnouncement(_)); + assert_matches_message!(&recording[1].0, Message::ChannelUpdate(_)); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastNodeAnnouncement if the + // route_handler.handle_node_announcement errors + #[test] + fn post_init_broadcast_node_announcement_route_handler_handle_announcement_errors() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_node_announcement_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }); + channel_handler.pending_events.lock().unwrap().push(BroadcastNodeAnnouncement { + msg: fake_node_announcement_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastNodeAnnouncement if the + // route_handler.handle_node_announcement returns false + // XXXBUG: Implementation does not check return value of handle_node_announcement, only that it didn't error + #[test] + fn post_init_broadcast_node_announcement_route_handler_handle_announcement_returns_false() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_node_announcement_return = Ok(false); + channel_handler.pending_events.lock().unwrap().push(BroadcastNodeAnnouncement { + msg: fake_node_announcement_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + // assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends the relevant messages when it receives a BroadcastNodeAnnouncement + #[test] + fn post_init_broadcast_node_announcement() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(BroadcastNodeAnnouncement { + msg: fake_node_announcement_msg!() + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::NodeAnnouncement(_)); + } + + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelUpdate if the + // route_handler.handle_channel_update errors + #[test] + fn post_init_broadcast_channel_update_route_handler_handle_update_errors() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Err(msgs::LightningError { err: "", action: msgs::ErrorAction::IgnoreError }); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelUpdate { + msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends nothing when it receives a BroadcastChannelUpdate if the + // route_handler.handle_channel_update returns false + // XXXBUG: Implementation does not check return value of handle_node_announcement, only that it didn't error + #[test] + fn post_init_broadcast_channel_update_route_handler_handle_update_returns_false() { + let channel_handler = TestChannelMessageHandler::new(); + let mut routing_handler = RoutingMessageHandlerTestStub::new(); + routing_handler.handle_channel_update_return = Ok(false); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelUpdate { + msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + // assert!(descriptor.get_recording().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends the relevant messages when it receives a BroadcastChannelAnnouncement + #[test] + fn post_init_broadcast_channel_update() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelUpdate { + msg: fake_channel_update_msg!() + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::ChannelUpdate(_)); + } + + // Test that a post-Init connection: + // * process_events() calls the correct route handler callback when it receives a + // PaymentFailureNetworkUpdate event + #[test] + fn post_init_payment_failure_network_update() { + let routing_handler = RoutingMessageHandlerTestSpy::new(); + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(PaymentFailureNetworkUpdate { + update: HTLCFailChannelUpdate::ChannelUpdateMessage { + msg: fake_channel_update_msg!() + } + }); + + let test_ctx = TestCtx::::with_channel_and_routing_handlers(channel_handler, routing_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + assert!(route_handler_called!(&test_ctx, handle_htlc_fail_channel_update)); + } + + // Test that a post-Init connection: + // * process_events() ignores a HandleErrorEvent::DisconnectPeer for an unknown peer + #[test] + fn post_init_handle_error_event_disconnect_unknown_peer() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(HandleError { + node_id: fake_public_key!(), + action: ErrorAction::DisconnectPeer { msg: None } + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + assert!(!descriptor.disconnect_called()); + assert!(descriptor.get_recording().is_empty()); + assert!(!peer_manager.get_peer_node_ids().is_empty()); + } + + // Test that a post-Init connection: + // * When process_events() receives a HandleErrorEvent::DisconnectPeer for an initialized peer w/ no message + // * get_peer_node_id() does not contain node_id + // * process_events() calls socket_disconnected() on the SocketDescriptor + #[test] + fn post_init_handle_error_event_disconnect_no_message() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(HandleError { + node_id: test_ctx_their_node_id!(), + action: ErrorAction::DisconnectPeer { msg: None } + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + assert!(descriptor.disconnect_called()); + assert!(descriptor.get_recording().is_empty()); + assert!(peer_manager.get_peer_node_ids().is_empty()); + } + + // Test that a post-Init connection: + // * When process_events() receives a HandleErrorEvent::DisconnectPeer for an initialized peer w/ a message + // * process_events() sends error message is sent through SocketDescriptor (attempted) + // * process_events() calls socket_disconnected() on the SocketDescriptor + // * get_peer_node_id() does not contain node_id + #[test] + fn post_init_handle_error_event_disconnect_message() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(HandleError { + node_id: test_ctx_their_node_id!(), + action: ErrorAction::DisconnectPeer { msg: Some(ErrorMessage { + channel_id: [0; 32], + data: "".to_string() + })} + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Error(_)); + assert!(descriptor.disconnect_called()); + assert!(peer_manager.get_peer_node_ids().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() ignores a HandleErrorEvent::IgnoreError for an initialized peer + #[test] + fn post_init_handle_error_event_ignore_error() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(HandleError { + node_id: test_ctx_their_node_id!(), + action: ErrorAction::IgnoreError + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + assert!(!descriptor.disconnect_called()); + assert!(descriptor.get_recording().is_empty()); + assert!(!peer_manager.get_peer_node_ids().is_empty()); + } + + // Test that a post-Init connection: + // * process_events() sends an error when it receives a HandleErrorEvent::SendErrorMessage for + // an initialized peer + #[test] + fn post_init_handle_error_event_send_error_message() { + let channel_handler = TestChannelMessageHandler::new(); + channel_handler.pending_events.lock().unwrap().push(HandleError { + node_id: test_ctx_their_node_id!(), + action: ErrorAction::SendErrorMessage { + msg: ErrorMessage { channel_id: [0; 32], data: "".to_string() } + } + }); + + let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Error(_)); + assert!(!descriptor.disconnect_called()); + assert!(!peer_manager.get_peer_node_ids().is_empty()); + } + + // ____ _ _____ _ _ + // | _ \(_)_ __ __ _ |_ _|__ ___| |_(_)_ __ __ _ + // | |_) | | '_ \ / _` | | |/ _ \/ __| __| | '_ \ / _` | + // | __/| | | | | (_| | | | __/\__ \ |_| | | | | (_| | + // |_| |_|_| |_|\__, | |_|\___||___/\__|_|_| |_|\__, | + // |___/ |___/ + + // Test that a post-Init connection: + // * read_event()/process_events() sends a Pong when it receives a Ping + #[test] + fn post_init_ping_creates_pong() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Ping(Ping { ponglen: 1, byteslen: 0 })); + + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + + peer_manager.process_events(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Pong(Pong { byteslen: 1})); + } + + // Test that a post-Init connection: + // * read_event()/process_events() ignores a Pong with ponglen > 65531 + #[test] + fn post_init_ping_ignores_large_pong() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + transport.borrow_mut().add_incoming_message(Message::Ping(Ping { ponglen: 65532, byteslen: 0 })); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + descriptor.assert_called_with(vec![]); + + peer_manager.process_events(); + descriptor.assert_called_with(vec![]); + } + + // Test that a post-Init connection: + // * timer_tick_occurred() generates a Ping + #[test] + fn post_init_timer_tick_occurred_generates_ping() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.timer_tick_occured(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[0].0, Message::Ping(_)); + } + + // Test that a post-Init connection: + // * timer_tick_occurred() calls socket_disconnected() on the SocketDescriptor + // * timer_tick_occurred() calls the peer_disconnected channel manager callback + // * get_peer_node_ids() does not contain disconnected node_id + #[test] + fn post_init_ping_no_pong_disconnects() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.timer_tick_occured(); + + // Elapsed time with no Pong + + peer_manager.timer_tick_occured(); + + assert!(descriptor.disconnect_called()); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!peer_manager.get_peer_node_ids().contains(&test_ctx.their_node_id)); + } + + // Test that a post-Init connection: + // * timer_tick_occurred() does not call socket_disconnected() if a Pong was received + // * get_peer_node_ids() contains node_id + #[test] + fn post_init_ping_with_pong() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.timer_tick_occured(); + + transport.borrow_mut().add_incoming_message(Message::Pong(Pong { byteslen: 64 })); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + + // Should notice the Pong and resend Ping + peer_manager.timer_tick_occured(); + + let recording = descriptor.get_recording(); + assert_matches_message!(&recording[1].0, Message::Ping(_)); + assert!(peer_manager.get_peer_node_ids().contains(&test_ctx.their_node_id)); + } + + // Test that a post-Init connection: + // * socket_disconnected() removes the node_id from get_peer_node_ids() + // * socket_disconnected() does not call disconnect_socket() on the SocketDescriptor + // * socket_disconnected() calls the peer_disconnected channel manager callback + #[test] + fn post_init_socket_disconnected() { + let test_ctx = TestCtx::::new(); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + + peer_manager.socket_disconnected(&descriptor); + + assert!(peer_manager.get_peer_node_ids().is_empty()); + assert!(!descriptor.disconnect_called()); + assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + } +} + #[cfg(test)] mod tests { use ln::peers::handler::{PeerManager, MessageHandler, SocketDescriptor}; @@ -1266,7 +3114,7 @@ mod tests { fn establish_connection<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { let secp_ctx = Secp256k1::new(); - let a_id = PublicKey::from_secret_key(&secp_ctx, &peer_a.our_node_secret); + let a_id = PublicKey::from_secret_key(&secp_ctx, &peer_a.inner.our_node_secret); let mut fd_a = FileDescriptor { fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())) }; let mut fd_b = FileDescriptor { fd: 1, outbound_data: Arc::new(Mutex::new(Vec::new())) }; let initial_data = peer_b.new_outbound_connection(a_id, fd_b.clone()).unwrap(); @@ -1292,20 +3140,20 @@ mod tests { let chan_handler = test_utils::TestChannelMessageHandler::new(); let mut peers = create_network(2, &cfgs); establish_connection(&peers[0], &peers[1]); - assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 1); + assert_eq!(peers[0].inner.peers.lock().unwrap().peers.len(), 1); let secp_ctx = Secp256k1::new(); - let their_id = PublicKey::from_secret_key(&secp_ctx, &peers[1].our_node_secret); + let their_id = PublicKey::from_secret_key(&secp_ctx, &peers[1].inner.our_node_secret); chan_handler.pending_events.lock().unwrap().push(events::MessageSendEvent::HandleError { node_id: their_id, action: msgs::ErrorAction::DisconnectPeer { msg: None }, }); assert_eq!(chan_handler.pending_events.lock().unwrap().len(), 1); - peers[0].message_handler.chan_handler = &chan_handler; + peers[0].inner.message_handler.chan_handler = &chan_handler; peers[0].process_events(); - assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 0); + assert_eq!(peers[0].inner.peers.lock().unwrap().peers.len(), 0); } #[test] @@ -1314,15 +3162,15 @@ mod tests { let cfgs = create_peermgr_cfgs(2); let peers = create_network(2, &cfgs); establish_connection(&peers[0], &peers[1]); - assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 1); + assert_eq!(peers[0].inner.peers.lock().unwrap().peers.len(), 1); // peers[0] awaiting_pong is set to true, but the Peer is still connected peers[0].timer_tick_occured(); - assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 1); + assert_eq!(peers[0].inner.peers.lock().unwrap().peers.len(), 1); // Since timer_tick_occured() is called again when awaiting_pong is true, all Peers are disconnected peers[0].timer_tick_occured(); - assert_eq!(peers[0].peers.lock().unwrap().peers.len(), 0); + assert_eq!(peers[0].inner.peers.lock().unwrap().peers.len(), 0); } #[test] @@ -1362,8 +3210,8 @@ mod tests { let peers = create_network(2, &cfgs); let (fd_0_to_1, fd_1_to_0) = establish_connection_and_read_events(&peers[0], &peers[1]); - let peer_0 = peers[0].peers.lock().unwrap(); - let peer_1 = peers[1].peers.lock().unwrap(); + let peer_0 = peers[0].inner.peers.lock().unwrap(); + let peer_1 = peers[1].inner.peers.lock().unwrap(); let peer_0_features = peer_1.peers.get(&fd_1_to_0).unwrap().their_features.as_ref(); let peer_1_features = peer_0.peers.get(&fd_0_to_1).unwrap().their_features.as_ref(); @@ -1379,8 +3227,8 @@ mod tests { let peers = create_network(2, &cfgs); let (fd_0_to_1, fd_1_to_0) = establish_connection_and_read_events(&peers[0], &peers[1]); - let peer_0 = peers[0].peers.lock().unwrap(); - let peer_1 = peers[1].peers.lock().unwrap(); + let peer_0 = peers[0].inner.peers.lock().unwrap(); + let peer_1 = peers[1].inner.peers.lock().unwrap(); let peer_0_features = peer_1.peers.get(&fd_1_to_0).unwrap().their_features.as_ref(); let peer_1_features = peer_0.peers.get(&fd_0_to_1).unwrap().their_features.as_ref(); diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index 6086352e2a1..5e8efb77d87 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -7,6 +7,10 @@ #[macro_use] mod test_util; +#[cfg(test)] +#[macro_use] +mod test_message_macros; + mod chacha; pub mod handler; mod hkdf5869rfc; diff --git a/lightning/src/ln/peers/test_message_macros.rs b/lightning/src/ln/peers/test_message_macros.rs new file mode 100644 index 00000000000..20504fde54c --- /dev/null +++ b/lightning/src/ln/peers/test_message_macros.rs @@ -0,0 +1,268 @@ +/// Helper macros that construct fake Messages. Useful in tests that don't care about the contents. + +macro_rules! fake_public_key { + () => {{ + let their_node_secret = SecretKey::from_slice(&[0x_11_u8; 32]).unwrap(); + PublicKey::from_secret_key(&Secp256k1::new(), &their_node_secret) + }} +} + +macro_rules! fake_valid_sig { + () => {{ + use bitcoin::secp256k1::ffi::Signature as FFISignature; + Signature::from(FFISignature::new()) + }} +} + +macro_rules! fake_open_channel_msg { + () => {{ + OpenChannel { + chain_hash: Default::default(), + temporary_channel_id: [0; 32], + funding_satoshis: 0, + push_msat: 0, + dust_limit_satoshis: 0, + max_htlc_value_in_flight_msat: 0, + channel_reserve_satoshis: 0, + htlc_minimum_msat: 0, + feerate_per_kw: 0, + to_self_delay: 0, + max_accepted_htlcs: 0, + funding_pubkey: fake_public_key!(), + revocation_basepoint: fake_public_key!(), + delayed_payment_basepoint: fake_public_key!(), + htlc_basepoint: fake_public_key!(), + payment_point: fake_public_key!(), + first_per_commitment_point: fake_public_key!(), + channel_flags: 0, + shutdown_scriptpubkey: OptionalField::Absent + } + }} +} + +macro_rules! fake_accept_channel_msg { + () => {{ + AcceptChannel { + temporary_channel_id: [0; 32], + dust_limit_satoshis: 0, + max_htlc_value_in_flight_msat: 0, + channel_reserve_satoshis: 0, + htlc_minimum_msat: 0, + minimum_depth: 0, + to_self_delay: 0, + max_accepted_htlcs: 0, + funding_pubkey: fake_public_key!(), + revocation_basepoint: fake_public_key!(), + payment_point: fake_public_key!(), + delayed_payment_basepoint: fake_public_key!(), + htlc_basepoint: fake_public_key!(), + first_per_commitment_point: fake_public_key!(), + shutdown_scriptpubkey: OptionalField::Absent + } + }} +} +macro_rules! fake_funding_created_msg { + () => {{ + FundingCreated { + temporary_channel_id: [0; 32], + funding_txid: Default::default(), + funding_output_index: 0, + signature: fake_valid_sig!() + } + }} +} + +macro_rules! fake_funding_signed_msg { + () => {{ + FundingSigned { + channel_id: [0; 32], + signature: fake_valid_sig!() + } + }} +} + +macro_rules! fake_funding_locked_msg { + () => {{ + FundingLocked { + channel_id: [0; 32], + next_per_commitment_point: fake_public_key!() + } + }} +} + +macro_rules! fake_shutdown_msg { + () => {{ + Shutdown { + channel_id: [0; 32], + scriptpubkey: Default::default() + } + }} +} + +macro_rules! fake_closing_signed_msg { + () => {{ + ClosingSigned { + channel_id: [0; 32], + fee_satoshis: 0, + signature: fake_valid_sig!() + } + }} +} + +macro_rules! fake_update_add_htlc_msg { + () => {{ + UpdateAddHTLC { + channel_id: [0; 32], + htlc_id: 0, + amount_msat: 0, + payment_hash: PaymentHash([0; 32]), + cltv_expiry: 0, + onion_routing_packet: OnionPacket { + version: 0, + public_key: Ok(fake_public_key!()), + hop_data: [0; 1300], + hmac: [0; 32] + } + } + }} +} + +macro_rules! fake_update_fulfill_htlc_msg { + () => {{ + UpdateFulfillHTLC { + channel_id: [0; 32], + htlc_id: 0, + payment_preimage: PaymentPreimage([0; 32]) + } + }} +} + + +macro_rules! fake_update_fail_htlc_msg { + () => {{ + UpdateFailHTLC { + channel_id: [0; 32], + htlc_id: 0, + reason: OnionErrorPacket { data: vec![] } + } + }} +} + +macro_rules! fake_update_fail_malformed_htlc_msg { + () => { + UpdateFailMalformedHTLC { + channel_id: [0; 32], + htlc_id: 0, + sha256_of_onion: [0; 32], + failure_code: 0 + } + } +} + +macro_rules! fake_commitment_signed_msg { + () => {{ + CommitmentSigned { + channel_id: [0; 32], + signature: fake_valid_sig!(), + htlc_signatures: vec![] + } + }} +} + +macro_rules! fake_revoke_and_ack_msg { + () => {{ + RevokeAndACK { + channel_id: [0; 32], + per_commitment_secret: [0; 32], + next_per_commitment_point: fake_public_key!() + } + }} +} +macro_rules! fake_update_fee_msg { + () => {{ + UpdateFee { + channel_id: [0; 32], + feerate_per_kw: 0 + } + }} +} + +macro_rules! fake_channel_reestablish_msg { + () => {{ + ChannelReestablish { + channel_id: [0; 32], + next_local_commitment_number: 0, + next_remote_commitment_number: 0, + data_loss_protect: OptionalField::Absent + } + }} +} + +macro_rules! fake_announcement_signatures_msg { + () => {{ + AnnouncementSignatures { + channel_id: [0;32], + short_channel_id: 0, + node_signature: fake_valid_sig!(), + bitcoin_signature: fake_valid_sig!() + } + }} +} + +macro_rules! fake_channel_announcement_msg { + ($channel_id: expr, $node_id_1: expr, $node_id_2: expr) => {{ + ChannelAnnouncement { + node_signature_1: fake_valid_sig!(), + node_signature_2: fake_valid_sig!(), + bitcoin_signature_1: fake_valid_sig!(), + bitcoin_signature_2: fake_valid_sig!(), + contents: UnsignedChannelAnnouncement { + features: ChannelFeatures::empty(), + chain_hash: Default::default(), + short_channel_id: $channel_id, + node_id_1: $node_id_1, + node_id_2: $node_id_2, + bitcoin_key_1: fake_public_key!(), + bitcoin_key_2: fake_public_key!(), + excess_data: vec![] + } + } + }} +} + +macro_rules! fake_node_announcement_msg { + () => {{ + NodeAnnouncement { + signature: fake_valid_sig!(), + contents: UnsignedNodeAnnouncement { + features: NodeFeatures::empty(), + timestamp: 0, + node_id: fake_public_key!(), + rgb: [0; 3], + alias: [0; 32], + addresses: vec![], + excess_address_data: vec![], + excess_data: vec![] + } + } + }} +} + +macro_rules! fake_channel_update_msg { + () => {{ + ChannelUpdate { + signature: fake_valid_sig!(), + contents: UnsignedChannelUpdate { + chain_hash: Default::default(), + short_channel_id: 0, + timestamp: 0, + flags: 0, + cltv_expiry_delta: 0, + htlc_minimum_msat: 0, + fee_base_msat: 0, + fee_proportional_millionths: 0, + excess_data: vec![] + } + } + }} +} diff --git a/lightning/src/ln/peers/test_util.rs b/lightning/src/ln/peers/test_util.rs index e384317ae34..f2f39fe82cd 100644 --- a/lightning/src/ln/peers/test_util.rs +++ b/lightning/src/ln/peers/test_util.rs @@ -4,13 +4,18 @@ use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use ln::peers::conduit::Conduit; -use ln::peers::handler::{SocketDescriptor, PayloadQueuer}; +use ln::peers::handler::{SocketDescriptor, PayloadQueuer, ITransport, PeerHandleError}; use ln::peers::transport::IPeerHandshake; use std::rc::Rc; -use std::cell::RefCell; +use std::cell::{RefCell}; use std::hash::Hash; use std::cmp; +use ln::wire::{Message, Encode}; +use bitcoin::hashes::core::ops::Deref; +use util::logger::Logger; +use util::ser::{Writeable, VecWriter}; +use ln::wire; macro_rules! assert_matches { ($actual:expr, $expected:pat) => { @@ -108,6 +113,9 @@ pub(super) struct SocketDescriptorMock { /// Vector of arguments and return values to send_data() used for validation send_recording: Rc, bool)>>>, + + /// Record if disconnect() was called on the Mock + disconnect_called: Rc>, } impl SocketDescriptorMock { @@ -116,7 +124,8 @@ impl SocketDescriptorMock { Self { unbounded: Rc::new(RefCell::new(true)), send_recording: Rc::new(RefCell::new(Vec::new())), - free_space: Rc::new(RefCell::new(0)) + free_space: Rc::new(RefCell::new(0)), + disconnect_called: Rc::new(RefCell::new(false)) } } @@ -134,6 +143,15 @@ impl SocketDescriptorMock { assert_eq!(expectation.as_slice(), self.send_recording.borrow().as_slice()) } + /// Retrieve the underlying recording for use in pattern matching or more complex value validation + pub(super) fn get_recording(&self) -> Vec<(Vec, bool)> { + self.send_recording.borrow().clone() + } + + pub(super) fn disconnect_called(&self) -> bool { + *self.disconnect_called.borrow_mut() + } + /// Allow future send_data() calls to succeed for the next added_room bytes. Not valid for /// unbounded mock descriptors pub(super) fn make_room(&mut self, added_room: usize) { @@ -142,6 +160,11 @@ impl SocketDescriptorMock { *free_space += added_room; } + + /// Clear the saved recording. Useful for resetting state between test phases. + pub(super) fn clear_recording(&mut self) { + self.send_recording.borrow_mut().clear(); + } } impl SocketDescriptor for SocketDescriptorMock { @@ -163,7 +186,9 @@ impl SocketDescriptor for SocketDescriptorMock { } fn disconnect_socket(&mut self) { - unimplemented!() + let mut val = self.disconnect_called.borrow_mut(); + assert!(!*val, "disconnect_socket() was alraedy called"); + *val = true; } } @@ -172,7 +197,8 @@ impl Clone for SocketDescriptorMock { Self { unbounded: self.unbounded.clone(), send_recording: self.send_recording.clone(), - free_space: self.free_space.clone() + free_space: self.free_space.clone(), + disconnect_called: self.disconnect_called.clone(), } } } @@ -203,3 +229,133 @@ impl PayloadQueuer for Vec> { } } +// Builder for TransportTestStub that allows tests to easily construct the Transport layer they +// want to use for their test. +pub(super) struct TransportStubBuilder { + stub: TransportStub, +} + +impl TransportStubBuilder { + pub(super) fn new() -> Self { + Self { + stub: TransportStub { + is_connected: false, + messages: vec![], + process_returns_error: false, + their_node_id: None, + } + } + } + + pub(super) fn set_connected(mut self, their_node_id: &PublicKey) -> Self { + self.stub.is_connected = true; + self.stub.their_node_id = Some(their_node_id.clone()); + self + } + + pub(super) fn process_returns_error(mut self) -> Self { + self.stub.process_returns_error(); + self + } + + pub(super) fn finish(self) -> TransportStub { + self.stub + } +} + +pub(super) struct TransportStub { + is_connected: bool, + messages: Vec, + process_returns_error: bool, + their_node_id: Option, +} + +// &RefCell passthrough to allow unit tests to pass in a Transport to the PeerManager, but later +// modify it to fail, return messages, etc. +impl<'a> ITransport for &'a RefCell { + fn new_outbound(_initiator_static_private_key: &SecretKey, _responder_static_public_key: &PublicKey, _initiator_ephemeral_private_key: &SecretKey) -> Self { + unimplemented!() + } + + fn set_up_outbound(&mut self) -> Vec { + self.borrow_mut().set_up_outbound() + } + + fn new_inbound(_responder_static_private_key: &SecretKey, _responder_ephemeral_private_key: &SecretKey) -> Self { + unimplemented!() + } + + fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result<(), String> { + self.borrow_mut().process_input(input, output_buffer) + } + + fn is_connected(&self) -> bool { + self.borrow().is_connected() + } + + fn get_their_node_id(&self) -> PublicKey { + self.borrow().get_their_node_id() + } + + fn drain_messages(&mut self, logger: L) -> Result, PeerHandleError> where L::Target: Logger { + self.borrow_mut().drain_messages(logger) + } + + fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, logger: L) where L::Target: Logger { + self.borrow_mut().enqueue_message(message, output_buffer, logger) + } +} + +impl TransportStub { + pub(super) fn process_returns_error(&mut self) { + self.process_returns_error = true; + } + + pub(super) fn add_incoming_message(&mut self, message: Message) { + assert!(self.is_connected, "Can't set messages on unconnected Transport"); + self.messages.push(message); + } +} + +// Stub implementation for ITransport with a fixed connection state. All enqueue_message() calls +// are placed directly into the PayloadQueuer unencrypted for easier test validation. +impl ITransport for TransportStub { + fn new_outbound(_initiator_static_private_key: &SecretKey, _responder_static_public_key: &PublicKey, _initiator_ephemeral_private_key: &SecretKey) -> Self { + unimplemented!() + } + + fn set_up_outbound(&mut self) -> Vec { + vec![] + } + + fn new_inbound(_responder_static_private_key: &SecretKey, _responder_ephemeral_private_key: &SecretKey) -> Self { + unimplemented!() + } + + fn process_input(&mut self, _input: &[u8], _output_buffer: &mut impl PayloadQueuer) -> Result<(), String> { + if self.process_returns_error { + Err("Oh no!".to_string()) + } else { + Ok(()) + } + } + + fn is_connected(&self) -> bool { + self.their_node_id.is_some() + } + + fn get_their_node_id(&self) -> PublicKey { + self.their_node_id.unwrap() + } + + fn drain_messages(&mut self, _logger: L) -> Result, PeerHandleError> where L::Target: Logger { + Ok(self.messages.drain(..).collect()) + } + + fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, _logger: L) + where L::Target: Logger { + let mut buffer = VecWriter(Vec::new()); + wire::write(message, &mut buffer).unwrap(); + output_buffer.push_back(buffer.0); + } +} \ No newline at end of file diff --git a/lightning/src/ln/wire.rs b/lightning/src/ln/wire.rs index 15a218060e6..77ed648ebc3 100644 --- a/lightning/src/ln/wire.rs +++ b/lightning/src/ln/wire.rs @@ -52,7 +52,7 @@ pub enum Message { /// A number identifying a message to determine how it is encoded on the wire. #[derive(Clone, Copy)] -pub struct MessageType(u16); +pub struct MessageType(pub u16); impl Message { /// Returns the type that was used to decode the message payload. diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 91af4202d28..8b9be9b8c89 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -22,8 +22,9 @@ use bitcoin::hash_types::{Txid, BlockHash}; use bitcoin::secp256k1::{SecretKey, PublicKey, Secp256k1, Signature}; +use ln::msgs::*; use std::time::{SystemTime, UNIX_EPOCH}; -use std::sync::Mutex; +use std::sync::{Mutex}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::{cmp, mem}; use std::collections::HashMap; @@ -131,6 +132,144 @@ impl chaininterface::BroadcasterInterface for TestBroadcaster { } } +/// Test Spy infrastructure for the ChannelMessageHandler trait that tests can use to validate +/// the correct callbacks were called. +macro_rules! generate_message_handler_called_fns { + ($($name: ident,)*) => { + pub struct ChannelMessageHandlerTestSpyCalledFns { + $( + pub $name: bool, + )* + } + impl ChannelMessageHandlerTestSpyCalledFns { + pub fn new() -> Self { + Self { + $( + $name: false, + )* + } + } + } + } +} +generate_message_handler_called_fns! { + handle_open_channel, + handle_accept_channel, + handle_funding_created, + handle_funding_signed, + handle_funding_locked, + handle_shutdown, + handle_closing_signed, + handle_update_add_htlc, + handle_update_fulfill_htlc, + handle_update_fail_htlc, + handle_update_fail_malformed_htlc, + handle_commitment_signed, + handle_revoke_and_ack, + handle_update_fee, + handle_announcement_signatures, + handle_channel_reestablish, + handle_error, + peer_connected, + peer_disconnected, +} + +pub struct ChannelMessageHandlerTestSpy { + pub called: Mutex +} + +impl ChannelMessageHandlerTestSpy { + pub fn new() -> Self { + Self { + called: Mutex::new(ChannelMessageHandlerTestSpyCalledFns::new()) + } + } +} + +impl msgs::ChannelMessageHandler for ChannelMessageHandlerTestSpy { + fn handle_open_channel(&self, _their_node_id: &PublicKey, _their_features: InitFeatures, _msg: &OpenChannel) { + self.called.lock().unwrap().handle_open_channel = true; + } + + fn handle_accept_channel(&self, _their_node_id: &PublicKey, _their_features: InitFeatures, _msg: &AcceptChannel) { + self.called.lock().unwrap().handle_accept_channel = true; + } + + fn handle_funding_created(&self, _their_node_id: &PublicKey, _msg: &FundingCreated) { + self.called.lock().unwrap().handle_funding_created = true; + } + + fn handle_funding_signed(&self, _their_node_id: &PublicKey, _msg: &FundingSigned) { + self.called.lock().unwrap().handle_funding_signed = true; + } + + fn handle_funding_locked(&self, _their_node_id: &PublicKey, _msg: &FundingLocked) { + self.called.lock().unwrap().handle_funding_locked = true; + } + + fn handle_shutdown(&self, _their_node_id: &PublicKey, _msg: &Shutdown) { + self.called.lock().unwrap().handle_shutdown = true; + } + + fn handle_closing_signed(&self, _their_node_id: &PublicKey, _msg: &ClosingSigned) { + self.called.lock().unwrap().handle_closing_signed = true; + } + + fn handle_update_add_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateAddHTLC) { + self.called.lock().unwrap().handle_update_add_htlc = true; + } + + fn handle_update_fulfill_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFulfillHTLC) { + self.called.lock().unwrap().handle_update_fulfill_htlc = true; + } + + fn handle_update_fail_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFailHTLC) { + self.called.lock().unwrap().handle_update_fail_htlc = true; + } + + fn handle_update_fail_malformed_htlc(&self, _their_node_id: &PublicKey, _msg: &UpdateFailMalformedHTLC) { + self.called.lock().unwrap().handle_update_fail_malformed_htlc = true; + } + + fn handle_commitment_signed(&self, _their_node_id: &PublicKey, _msg: &CommitmentSigned) { + self.called.lock().unwrap().handle_commitment_signed = true; + } + + fn handle_revoke_and_ack(&self, _their_node_id: &PublicKey, _msg: &RevokeAndACK) { + self.called.lock().unwrap().handle_revoke_and_ack = true; + } + + fn handle_update_fee(&self, _their_node_id: &PublicKey, _msg: &UpdateFee) { + self.called.lock().unwrap().handle_update_fee = true; + } + + fn handle_announcement_signatures(&self, _their_node_id: &PublicKey, _msg: &AnnouncementSignatures) { + self.called.lock().unwrap().handle_announcement_signatures = true; + } + + fn peer_disconnected(&self, _their_node_id: &PublicKey, _no_connection_possible: bool) { + self.called.lock().unwrap().peer_disconnected = true; + } + + fn peer_connected(&self, _their_node_id: &PublicKey, _msg: &Init) { + self.called.lock().unwrap().peer_connected = true; + } + + fn handle_channel_reestablish(&self, _their_node_id: &PublicKey, _msg: &ChannelReestablish) { + self.called.lock().unwrap().handle_channel_reestablish = true; + } + + fn handle_error(&self, _their_node_id: &PublicKey, _msg: &ErrorMessage) { + self.called.lock().unwrap().handle_error = true; + } +} + +impl events::MessageSendEventsProvider for ChannelMessageHandlerTestSpy { + fn get_and_clear_pending_msg_events(&self) -> Vec { + vec![] + } +} + pub struct TestChannelMessageHandler { pub pending_events: Mutex>, } @@ -221,6 +360,132 @@ fn get_dummy_channel_update(short_chan_id: u64) -> msgs::ChannelUpdate { } } +/// Test Stub for the RoutingMessageHandler. +pub struct RoutingMessageHandlerTestStub { + pub handle_node_announcement_return: Result, + pub handle_channel_announcement_return: Result, + pub handle_channel_update_return: Result, + pub should_request_full_sync_return: bool +} + +impl RoutingMessageHandlerTestStub { + pub fn new() -> Self { + Self { + handle_node_announcement_return: Ok(true), + handle_channel_announcement_return: Ok(true), + handle_channel_update_return: Ok(true), + should_request_full_sync_return: true + } + } +} + +impl RoutingMessageHandler for RoutingMessageHandlerTestStub { + fn handle_node_announcement(&self, _msg: &NodeAnnouncement) -> Result { + self.handle_node_announcement_return.clone() + } + + fn handle_channel_announcement(&self, _msg: &ChannelAnnouncement) -> Result { + self.handle_channel_announcement_return.clone() + } + + fn handle_channel_update(&self, _msg: &ChannelUpdate) -> Result { + self.handle_channel_update_return.clone() + } + + fn handle_htlc_fail_channel_update(&self, _update: &HTLCFailChannelUpdate) { } + + fn get_next_channel_announcements(&self, _starting_point: u64, _batch_amount: u8) -> Vec<(ChannelAnnouncement, Option, Option)> { + vec![] + } + + fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec { + vec![] + } + + fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool { + self.should_request_full_sync_return + } +} + +/// Test Spy infrastructure for the RoutingMessageHandler trait that tests can use to validate +/// the correct callbacks were called. +macro_rules! generate_routing_handler_called_fns { + ($($name: ident,)*) => { + pub struct RoutingMessageHandlerTestSpyCalledFns { + $( + pub $name: bool, + )* + } + impl RoutingMessageHandlerTestSpyCalledFns { + pub fn new() -> Self { + Self { + $( + $name: false, + )* + } + } + } + } +} + +generate_routing_handler_called_fns!( + handle_node_announcement, + handle_channel_announcement, + handle_channel_update, + handle_htlc_fail_channel_update, + get_next_channel_announcements, + get_next_node_announcements, + should_request_full_sync, +); + +pub struct RoutingMessageHandlerTestSpy { + pub called: Mutex +} + +impl RoutingMessageHandlerTestSpy { + pub fn new() -> Self { + Self { + called: Mutex::new(RoutingMessageHandlerTestSpyCalledFns::new()) + } + } +} + +impl RoutingMessageHandler for RoutingMessageHandlerTestSpy { + fn handle_node_announcement(&self, _msg: &NodeAnnouncement) -> Result { + self.called.lock().unwrap().handle_node_announcement = true; + Ok(true) + } + + fn handle_channel_announcement(&self, _msg: &ChannelAnnouncement) -> Result { + self.called.lock().unwrap().handle_channel_announcement = true; + Ok(true) + } + + fn handle_channel_update(&self, _msg: &ChannelUpdate) -> Result { + self.called.lock().unwrap().handle_channel_update = true; + Ok(true) + } + + fn handle_htlc_fail_channel_update(&self, _update: &HTLCFailChannelUpdate) { + self.called.lock().unwrap().handle_htlc_fail_channel_update = true; + } + + fn get_next_channel_announcements(&self, _starting_point: u64, _batch_amount: u8) -> Vec<(ChannelAnnouncement, Option, Option)> { + self.called.lock().unwrap().get_next_channel_announcements = true; + vec![] + } + + fn get_next_node_announcements(&self, _starting_point: Option<&PublicKey>, _batch_amount: u8) -> Vec { + self.called.lock().unwrap().get_next_node_announcements = true; + vec![] + } + + fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool { + self.called.lock().unwrap().should_request_full_sync = true; + true + } +} + pub struct TestRoutingMessageHandler { pub chan_upds_recvd: AtomicUsize, pub chan_anns_recvd: AtomicUsize, From eadc443377c2170488177dfaf22f79ab754d5c0a Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sat, 5 Sep 2020 14:30:40 -0700 Subject: [PATCH 78/96] refactor: Destructure read_event() path Pass in all the in/out parameters individually instead of taking everything out of peer. The important thing to notice here is that the pending_outbound_buffer parameter MUST be an OutboundQueue and CANNOT be an 'impl PayloadQueuer'. This demonstrates that the read_event() function has the ability to flush() since it can use the SocketDescriptorFlusher interface. This should be illegal due to the invariant that read_event() never calls back into the SocketDescriptor. This is one of the motivations of using trait bounds in argument position as a defensive programing technique to prohibit functions from taking actions that shouldn't be allowed even if they have access to the object. Future patches will fix this bug and ensure the type system enforces this bug from happening again. This is a short-lived destructure that will be recombined once the dependencies are cleaned up. --- lightning/src/ln/peers/handler.rs | 336 ++++++++++++++++-------------- 1 file changed, 180 insertions(+), 156 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index f6b316e3dc5..d8d406b0226 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -509,61 +509,66 @@ impl) { - while !peer.pending_outbound_buffer.is_blocked() { - let queue_space = peer.pending_outbound_buffer.queue_space(); + fn do_attempt_write_data( + &self, + descriptor: &mut Descriptor, + sync_status: &mut InitSyncTracker, + transport: &mut impl ITransport, + pending_outbound_buffer: &mut Q) { + while !pending_outbound_buffer.is_blocked() { + let queue_space = pending_outbound_buffer.queue_space(); if queue_space > 0 { - match peer.sync_status { - InitSyncTracker::NoSyncRequested => {}, - InitSyncTracker::ChannelsSyncing(c) if c < 0xffff_ffff_ffff_ffff => { + match sync_status { + &mut InitSyncTracker::NoSyncRequested => {}, + &mut InitSyncTracker::ChannelsSyncing(c) if c < 0xffff_ffff_ffff_ffff => { let steps = ((queue_space + 2) / 3) as u8; let all_messages = self.message_handler.route_handler.get_next_channel_announcements(c, steps); for &(ref announce, ref update_a_option, ref update_b_option) in all_messages.iter() { - peer.transport.enqueue_message(announce, &mut peer.pending_outbound_buffer, &*self.logger); + transport.enqueue_message(announce, pending_outbound_buffer, &*self.logger); if let &Some(ref update_a) = update_a_option { - peer.transport.enqueue_message(update_a, &mut peer.pending_outbound_buffer, &*self.logger); + transport.enqueue_message(update_a, pending_outbound_buffer, &*self.logger); } if let &Some(ref update_b) = update_b_option { - peer.transport.enqueue_message(update_b, &mut peer.pending_outbound_buffer, &*self.logger); + transport.enqueue_message(update_b, pending_outbound_buffer, &*self.logger); } - peer.sync_status = InitSyncTracker::ChannelsSyncing(announce.contents.short_channel_id + 1); + *sync_status = InitSyncTracker::ChannelsSyncing(announce.contents.short_channel_id + 1); } if all_messages.is_empty() || all_messages.len() != steps as usize { - peer.sync_status = InitSyncTracker::ChannelsSyncing(0xffff_ffff_ffff_ffff); + *sync_status = InitSyncTracker::ChannelsSyncing(0xffff_ffff_ffff_ffff); } }, - InitSyncTracker::ChannelsSyncing(c) if c == 0xffff_ffff_ffff_ffff => { + &mut InitSyncTracker::ChannelsSyncing(c) if c == 0xffff_ffff_ffff_ffff => { let steps = queue_space as u8; let all_messages = self.message_handler.route_handler.get_next_node_announcements(None, steps); for msg in all_messages.iter() { - peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); - peer.sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); + transport.enqueue_message(msg, pending_outbound_buffer, &*self.logger); + *sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); } if all_messages.is_empty() || all_messages.len() != steps as usize { - peer.sync_status = InitSyncTracker::NoSyncRequested; + *sync_status = InitSyncTracker::NoSyncRequested; } }, - InitSyncTracker::ChannelsSyncing(_) => unreachable!(), - InitSyncTracker::NodesSyncing(key) => { + &mut InitSyncTracker::ChannelsSyncing(_) => unreachable!(), + &mut InitSyncTracker::NodesSyncing(key) => { let steps = queue_space as u8; let all_messages = self.message_handler.route_handler.get_next_node_announcements(Some(&key), steps); for msg in all_messages.iter() { - peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); - peer.sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); + transport.enqueue_message(msg, pending_outbound_buffer, &*self.logger); + *sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); } if all_messages.is_empty() || all_messages.len() != steps as usize { - peer.sync_status = InitSyncTracker::NoSyncRequested; + *sync_status = InitSyncTracker::NoSyncRequested; } }, } } // No messages to send - if peer.pending_outbound_buffer.is_empty() { + if pending_outbound_buffer.is_empty() { break; } - peer.pending_outbound_buffer.try_flush_one(descriptor); + pending_outbound_buffer.try_flush_one(descriptor); } } @@ -573,14 +578,23 @@ impl panic!("Descriptor for write_event is not already known to PeerManager"), Some(peer) => { peer.pending_outbound_buffer.unblock(); - self.do_attempt_write_data(descriptor, peer); + self.do_attempt_write_data(descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); } }; Ok(()) } fn read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8]) -> Result { - match self.do_read_event(peer_descriptor, data) { + let result = { + let peers = &mut *self.peers.lock().unwrap(); + let peer = match peers.peers.get_mut(peer_descriptor) { + None => panic!("Descriptor for read_event is not already known to PeerManager"), + Some(peer) => peer + }; + self.do_read_event(peer_descriptor, data, peer.outbound, &mut peer.sync_status, &mut peer.awaiting_pong, &mut peer.their_features, &mut peer.transport, &mut peer.pending_outbound_buffer, &mut peers.node_id_to_descriptor, &mut peers.peers_needing_send) + }; + + match result { Ok(res) => Ok(res), Err(e) => { self.disconnect_event_internal(peer_descriptor, e.no_connection_possible); @@ -595,113 +609,123 @@ impl Result { + fn do_read_event(&self, + peer_descriptor: &mut Descriptor, + data: &[u8], + outbound: bool, + sync_status: &mut InitSyncTracker, + awaiting_pong: &mut bool, + their_features: &mut Option, + transport: &mut impl ITransport, + pending_outbound_buffer: &mut OutboundQueue, + node_id_to_descriptor: &mut HashMap, + peers_needing_send: &mut HashSet) -> Result { let pause_read = { - let mut peers_lock = self.peers.lock().unwrap(); - let peers = &mut *peers_lock; - let pause_read = match peers.peers.get_mut(peer_descriptor) { - None => panic!("Descriptor for read_event is not already known to PeerManager"), - Some(peer) => { - - match peer.transport.process_input(data, &mut peer.pending_outbound_buffer) { - Err(e) => { - log_trace!(self.logger, "Error while processing input: {}", e); - return Err(PeerHandleError { no_connection_possible: false }) - }, - Ok(_) => { - - // If the transport is newly connected, do the appropriate set up for the connection - if peer.transport.is_connected() { - let their_node_id = peer.transport.get_their_node_id(); - - match peers.node_id_to_descriptor.entry(their_node_id.clone()) { - hash_map::Entry::Occupied(entry) => { - if entry.get() != peer_descriptor { - // Existing entry in map is from a different descriptor, this is a duplicate - log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(&their_node_id)); - return Err(PeerHandleError { no_connection_possible: false }); - } else { - // read_event for existing peer - } - }, - hash_map::Entry::Vacant(entry) => { - log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&their_node_id)); - - if peer.outbound { - let mut features = InitFeatures::known(); - if !self.message_handler.route_handler.should_request_full_sync(&their_node_id) { - features.clear_initial_routing_sync(); - } + match transport.process_input(data, pending_outbound_buffer) { + Err(e) => { + log_trace!(self.logger, "Error while processing input: {}", e); + return Err(PeerHandleError { no_connection_possible: false }) + }, + Ok(_) => { + + // If the transport is newly connected, do the appropriate set up for the connection + if transport.is_connected() { + let their_node_id = transport.get_their_node_id(); + + match node_id_to_descriptor.entry(their_node_id.clone()) { + hash_map::Entry::Occupied(entry) => { + if entry.get() != peer_descriptor { + // Existing entry in map is from a different descriptor, this is a duplicate + log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(&their_node_id)); + return Err(PeerHandleError { no_connection_possible: false }); + } else { + // read_event for existing peer + } + }, + hash_map::Entry::Vacant(entry) => { + log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&their_node_id)); - let resp = msgs::Init { features }; - self.enqueue_message(&mut peers.peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, peer_descriptor, &resp); - } - entry.insert(peer_descriptor.clone()); + if outbound { + let mut features = InitFeatures::known(); + if !self.message_handler.route_handler.should_request_full_sync(&their_node_id) { + features.clear_initial_routing_sync(); } + + let resp = msgs::Init { features }; + self.enqueue_message(peers_needing_send, transport, pending_outbound_buffer, peer_descriptor, &resp); } + entry.insert(peer_descriptor.clone()); } } } + } + } - let received_messages = peer.transport.drain_messages(&*self.logger)?; - - for message in received_messages { - macro_rules! try_potential_handleerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(e) => { - match e.action { - msgs::ErrorAction::DisconnectPeer { msg: _ } => { - //TODO: Try to push msg - log_trace!(self.logger, "Got Err handling message, disconnecting peer because {}", e.err); - return Err(PeerHandleError{ no_connection_possible: false }); - }, - msgs::ErrorAction::IgnoreError => { - log_trace!(self.logger, "Got Err handling message, ignoring because {}", e.err); - continue; - }, - msgs::ErrorAction::SendErrorMessage { msg } => { - log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - self.enqueue_message(&mut peers.peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, peer_descriptor, &msg); - continue; - }, - } - } - }; - } - } - - if let Err(handling_error) = self.handle_message(&mut peers.peers_needing_send, peer, peer_descriptor.clone(), message){ - match handling_error { - MessageHandlingError::PeerHandleError(e) => { return Err(e) }, - MessageHandlingError::LightningError(e) => { - try_potential_handleerror!(Err(e)); - }, + let received_messages = transport.drain_messages(&*self.logger)?; + + for message in received_messages { + macro_rules! try_potential_handleerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(e) => { + match e.action { + msgs::ErrorAction::DisconnectPeer { msg: _ } => { + //TODO: Try to push msg + log_trace!(self.logger, "Got Err handling message, disconnecting peer because {}", e.err); + return Err(PeerHandleError{ no_connection_possible: false }); + }, + msgs::ErrorAction::IgnoreError => { + log_trace!(self.logger, "Got Err handling message, ignoring because {}", e.err); + continue; + }, + msgs::ErrorAction::SendErrorMessage { msg } => { + log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); + self.enqueue_message(peers_needing_send, transport, pending_outbound_buffer, peer_descriptor, &msg); + continue; + }, + } } - } + }; } + } - self.do_attempt_write_data(peer_descriptor, peer); - - peer.pending_outbound_buffer.queue_space() == 0 // pause_read + if let Err(handling_error) = self.handle_message(peers_needing_send, peer_descriptor, message, outbound, sync_status, awaiting_pong, their_features, transport, pending_outbound_buffer) { + match handling_error { + MessageHandlingError::PeerHandleError(e) => { return Err(e) }, + MessageHandlingError::LightningError(e) => { + try_potential_handleerror!(Err(e)); + }, + } } - }; + } + + self.do_attempt_write_data(peer_descriptor, sync_status, transport, pending_outbound_buffer); - pause_read + pending_outbound_buffer.queue_space() == 0 // pause_read }; Ok(pause_read) } /// Process an incoming message and return a decision (ok, lightning error, peer handling error) regarding the next action with the peer - fn handle_message(&self, peers_needing_send: &mut HashSet, peer: &mut Peer, peer_descriptor: Descriptor, message: wire::Message) -> Result<(), MessageHandlingError> { - log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(peer.transport.get_their_node_id())); + fn handle_message(&self, + peers_needing_send: &mut HashSet, + peer_descriptor: &mut Descriptor, + message: wire::Message, + outbound: bool, + sync_status: &mut InitSyncTracker, + awaiting_pong: &mut bool, + their_features: &mut Option, + transport: &mut impl ITransport, + pending_outbound_buffer: &mut OutboundQueue + ) -> Result<(), MessageHandlingError> { + log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(transport.get_their_node_id())); // Need an Init as first message if let wire::Message::Init(_) = message { - } else if peer.their_features.is_none() { - log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(peer.transport.get_their_node_id())); + } else if their_features.is_none() { + log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(transport.get_their_node_id())); return Err(PeerHandleError{ no_connection_possible: false }.into()); } @@ -716,7 +740,7 @@ impl { let mut data_is_printable = true; @@ -761,11 +785,11 @@ impl { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, &peer_descriptor, &resp); + self.enqueue_message(peers_needing_send, transport, pending_outbound_buffer, &peer_descriptor, &resp); } }, wire::Message::Pong(_msg) => { - peer.awaiting_pong = false; + *awaiting_pong = false; }, // Channel messages: wire::Message::OpenChannel(msg) => { - self.message_handler.chan_handler.handle_open_channel(&peer.transport.get_their_node_id(), peer.their_features.clone().unwrap(), &msg); + self.message_handler.chan_handler.handle_open_channel(&transport.get_their_node_id(), their_features.clone().unwrap(), &msg); }, wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&peer.transport.get_their_node_id(), peer.their_features.clone().unwrap(), &msg); + self.message_handler.chan_handler.handle_accept_channel(&transport.get_their_node_id(), their_features.clone().unwrap(), &msg); }, wire::Message::FundingCreated(msg) => { - self.message_handler.chan_handler.handle_funding_created(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_funding_created(&transport.get_their_node_id(), &msg); }, wire::Message::FundingSigned(msg) => { - self.message_handler.chan_handler.handle_funding_signed(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_funding_signed(&transport.get_their_node_id(), &msg); }, wire::Message::FundingLocked(msg) => { - self.message_handler.chan_handler.handle_funding_locked(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_funding_locked(&transport.get_their_node_id(), &msg); }, wire::Message::Shutdown(msg) => { - self.message_handler.chan_handler.handle_shutdown(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_shutdown(&transport.get_their_node_id(), &msg); }, wire::Message::ClosingSigned(msg) => { - self.message_handler.chan_handler.handle_closing_signed(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_closing_signed(&transport.get_their_node_id(), &msg); }, // Commitment messages: wire::Message::UpdateAddHTLC(msg) => { - self.message_handler.chan_handler.handle_update_add_htlc(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_add_htlc(&transport.get_their_node_id(), &msg); }, wire::Message::UpdateFulfillHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fulfill_htlc(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fulfill_htlc(&transport.get_their_node_id(), &msg); }, wire::Message::UpdateFailHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_htlc(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fail_htlc(&transport.get_their_node_id(), &msg); }, wire::Message::UpdateFailMalformedHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&transport.get_their_node_id(), &msg); }, wire::Message::CommitmentSigned(msg) => { - self.message_handler.chan_handler.handle_commitment_signed(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_commitment_signed(&transport.get_their_node_id(), &msg); }, wire::Message::RevokeAndACK(msg) => { - self.message_handler.chan_handler.handle_revoke_and_ack(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_revoke_and_ack(&transport.get_their_node_id(), &msg); }, wire::Message::UpdateFee(msg) => { - self.message_handler.chan_handler.handle_update_fee(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fee(&transport.get_their_node_id(), &msg); }, wire::Message::ChannelReestablish(msg) => { - self.message_handler.chan_handler.handle_channel_reestablish(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_channel_reestablish(&transport.get_their_node_id(), &msg); }, // Routing messages: wire::Message::AnnouncementSignatures(msg) => { - self.message_handler.chan_handler.handle_announcement_signatures(&peer.transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_announcement_signatures(&transport.get_their_node_id(), &msg); }, wire::Message::ChannelAnnouncement(msg) => { let should_forward = match self.message_handler.route_handler.handle_channel_announcement(&msg) { @@ -925,7 +949,7 @@ impl { log_trace!(self.logger, "Handling SendOpenChannel event in peer_handler for node {} for channel {}", @@ -937,7 +961,7 @@ impl { log_trace!(self.logger, "Handling SendFundingCreated event in peer_handler for node {} for channel {} (which becomes {})", @@ -951,7 +975,7 @@ impl { log_trace!(self.logger, "Handling SendFundingSigned event in peer_handler for node {} for channel {}", @@ -964,7 +988,7 @@ impl { log_trace!(self.logger, "Handling SendFundingLocked event in peer_handler for node {} for channel {}", @@ -976,7 +1000,7 @@ impl { log_trace!(self.logger, "Handling SendAnnouncementSignatures event in peer_handler for node {} for channel {})", @@ -989,7 +1013,7 @@ impl { log_trace!(self.logger, "Handling UpdateHTLCs event in peer_handler for node {} with {} adds, {} fulfills, {} fails for channel {}", @@ -1019,7 +1043,7 @@ impl { log_trace!(self.logger, "Handling SendRevokeAndACK event in peer_handler for node {} for channel {}", @@ -1031,7 +1055,7 @@ impl { log_trace!(self.logger, "Handling SendClosingSigned event in peer_handler for node {} for channel {}", @@ -1043,7 +1067,7 @@ impl { log_trace!(self.logger, "Handling Shutdown event in peer_handler for node {} for channel {}", @@ -1055,7 +1079,7 @@ impl { log_trace!(self.logger, "Handling SendChannelReestablish event in peer_handler for node {} for channel {}", @@ -1067,7 +1091,7 @@ impl { log_trace!(self.logger, "Handling BroadcastChannelAnnouncement event in peer_handler for short channel id {}", msg.contents.short_channel_id); @@ -1086,7 +1110,7 @@ impl self.do_attempt_write_data(&mut descriptor, peer), + Some(peer) => self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer), None => panic!("Inconsistent peers set state!"), } } @@ -1234,7 +1258,7 @@ impl Date: Sat, 5 Sep 2020 14:46:54 -0700 Subject: [PATCH 79/96] fix: Fix reentrancy bug in read_event() Per the external documentation, there is an invariant that read_event() will not call back into the SocketDescriptor, but the actual code flushed the outbound queue. Fix the bug and use the type system to guarantee this behavior in the future. By changing the function parameters to use `impl PayloadQueuer` the function will only have access to functions on that interface throughout the execution, but still be able to pass the OutboundQueue object since it satisfies the trait bounds. Functions such as enqueue_message() also take a `impl PayloadQueuer` so they can be called from that context, but functions that need the SocketDescriptorFlusher interface will fail at compile-time and point to the issue before any tests need to be run. This also fixes up tests and the tokio implementation that did not implement the proper behavior and relied on read_event() calling send_data(). --- lightning-net-tokio/src/lib.rs | 23 +++-- lightning/src/ln/peers/handler.rs | 163 +++++++++++++++--------------- lightning/src/util/test_utils.rs | 85 ++++++++++++++++ 3 files changed, 177 insertions(+), 94 deletions(-) diff --git a/lightning-net-tokio/src/lib.rs b/lightning-net-tokio/src/lib.rs index 402a6bc7d5e..da93794353a 100644 --- a/lightning-net-tokio/src/lib.rs +++ b/lightning-net-tokio/src/lib.rs @@ -180,17 +180,20 @@ impl Connection { Ok(len) => { prepare_read_write_call!(); let read_res = peer_manager.read_event(&mut our_descriptor, &buf[0..len]); - let mut us_lock = us.lock().unwrap(); - match read_res { - Ok(pause_read) => { - if pause_read { - us_lock.read_paused = true; - } - Self::event_trigger(&mut us_lock); - }, - Err(e) => shutdown_socket!(e, Disconnect::CloseConnection), + { + let mut us_lock = us.lock().unwrap(); + match read_res { + Ok(pause_read) => { + if pause_read { + us_lock.read_paused = true; + } + Self::event_trigger(&mut us_lock); + }, + Err(e) => shutdown_socket!(e, Disconnect::CloseConnection), + } + us_lock.block_disconnect_socket = false; } - us_lock.block_disconnect_socket = false; + peer_manager.process_events(); }, Err(e) => shutdown_socket!(e, Disconnect::PeerDisconnected), }, diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index d8d406b0226..83926c4c82c 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -617,7 +617,7 @@ impl, transport: &mut impl ITransport, - pending_outbound_buffer: &mut OutboundQueue, + pending_outbound_buffer: &mut impl PayloadQueuer, node_id_to_descriptor: &mut HashMap, peers_needing_send: &mut HashSet) -> Result { let pause_read = { @@ -657,6 +657,12 @@ impl, transport: &mut impl ITransport, - pending_outbound_buffer: &mut OutboundQueue + pending_outbound_buffer: &mut impl PayloadQueuer ) -> Result<(), MessageHandlingError> { log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(transport.get_their_node_id())); @@ -1392,6 +1396,7 @@ mod unit_tests { assert_matches!(peer_manager.read_event($descriptor, &[]), Ok(_)); // Drain pre-init data from descriptor in recording + peer_manager.process_events(); $descriptor.clear_recording(); peer_manager @@ -1549,7 +1554,7 @@ mod unit_tests { } // Test that an inbound connection with a connected Transport and queued Init message: - // * XXXBUG: does not send anything in read_event() + // * read_event() does not send anything in read_event() // * read_event() calls the peer_connected channel manager callback // * process_events() sends an Init message #[test] @@ -1565,7 +1570,7 @@ mod unit_tests { assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); assert!(channel_handler_called!(&test_ctx, peer_connected)); - // descriptor.assert_called_with(vec![]); + descriptor.assert_called_with(vec![]); peer_manager.process_events(); @@ -1589,7 +1594,9 @@ mod unit_tests { new_inbound!(peer_manager, descriptor, &mut transport); - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(true)); + // Process Init through to outbound queue + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(false)); + peer_manager.process_events(); // Call w/o write_buffer_space_avail still returns Ok(true) assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(true)); @@ -1603,8 +1610,6 @@ mod unit_tests { peer_manager.write_buffer_space_avail(&mut descriptor).unwrap(); assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - peer_manager.process_events(); - let recording = descriptor.get_recording(); assert_matches_message!(&recording[0].0, Message::Init(_)); assert!(channel_handler_called!(&test_ctx, peer_connected)); @@ -1612,7 +1617,7 @@ mod unit_tests { // Test that an outbound connection with a connected Transport: // * get_peer_node_ids() does not contain the node_id - // * XXXBUG: does not send anything in read_event() + // * read_event() does not send anything // * process_events() sends an Init message #[test] fn outbound_connected_transport_sends_init_in_process_events() { @@ -1623,8 +1628,7 @@ mod unit_tests { new_outbound!(peer_manager, descriptor, &mut transport); assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - // XXXBUG: Should not call back into descriptor - // descriptor.assert_called_with(vec![]); + descriptor.assert_called_with(vec![]); assert!(peer_manager.get_peer_node_ids().is_empty()); @@ -1999,7 +2003,7 @@ mod unit_tests { } // Test generator macro to reduce duplication across the broadcast message cases. - // (test name, expression that returns a routing handler, message that will be queued, closure taking (peer_manager, descriptor) that does the validation) + // (test name, expression that returns a routing handler, message that will be queued, closure taking (descriptor) that does the validation) macro_rules! generate_broadcast_message_test { ($test_name: ident, $routing_handler: expr, $message: expr, $validation: tt) => { #[test] @@ -2010,8 +2014,10 @@ mod unit_tests { let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); transport.borrow_mut().add_incoming_message($message); + assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + peer_manager.process_events(); - $validation(peer_manager, descriptor) + $validation(descriptor) } } } @@ -2025,9 +2031,8 @@ mod unit_tests { routing_handler }, Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), - (| peer_manager: PeerManagerImpl>, mut descriptor | - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)) - )); + (| _descriptor | { }) + ); // Test that a post-Init connection: // * read_event() returns Ok(_) if a ChannelAnnouncement message is received and the routing handler @@ -2039,8 +2044,7 @@ mod unit_tests { routing_handler }, Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + (| descriptor: SocketDescriptorMock | { let recording = descriptor.get_recording(); assert_matches_message!(&recording[0].0, Message::Error(_)) } @@ -2055,10 +2059,8 @@ mod unit_tests { routing_handler }, Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - } - )); + (| _descriptor | { }) + ); // Test that a post-Init connection: // * read_event() returns Ok(_) if a ChannelAnnouncement message is received and the routing handler @@ -2069,10 +2071,8 @@ mod unit_tests { routing_handler }, Message::ChannelAnnouncement(fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!())), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - } - )); + (| _descriptor | { }) + ); // Test that a post-Init connection: // * read_event() returns Ok(_) if a NodeAnnouncement message is received and the routing handler @@ -2083,8 +2083,7 @@ mod unit_tests { routing_handler }, Message::NodeAnnouncement(fake_node_announcement_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)) + (| _descriptor | { } )); // Test that a post-Init connection: @@ -2097,8 +2096,7 @@ mod unit_tests { routing_handler }, Message::NodeAnnouncement(fake_node_announcement_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + (| descriptor: SocketDescriptorMock | { let recording = descriptor.get_recording(); assert_matches_message!(&recording[0].0, Message::Error(_)) } @@ -2113,10 +2111,8 @@ mod unit_tests { routing_handler }, Message::NodeAnnouncement(fake_node_announcement_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - } - )); + (| _descriptor | { }) + ); // Test that a post-Init connection: // * read_event() returns Ok(_) if a NodeAnnouncement message is received and the routing handler @@ -2127,10 +2123,8 @@ mod unit_tests { routing_handler }, Message::NodeAnnouncement(fake_node_announcement_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - } - )); + (| _descriptor | { }) + ); // Test that a post-Init connection: // * read_event() returns Ok(_) if a ChannelUpdate message is received and the routing handler @@ -2141,9 +2135,8 @@ mod unit_tests { routing_handler }, Message::ChannelUpdate(fake_channel_update_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)) - )); + (| _descriptor | { }) + ); // Test that a post-Init connection: // * read_event() returns Ok(_) if a ChannelUpdate message is received and the routing handler @@ -2155,8 +2148,7 @@ mod unit_tests { routing_handler }, Message::ChannelUpdate(fake_channel_update_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); + (| descriptor: SocketDescriptorMock | { let recording = descriptor.get_recording(); assert_matches_message!(&recording[0].0, Message::Error(_)) } @@ -2171,10 +2163,8 @@ mod unit_tests { routing_handler }, Message::ChannelUpdate(fake_channel_update_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - } - )); + (| _descriptor | { }) + ); // Test that a post-Init connection: // * read_event() returns Ok(_) if a ChannelUpdate message is received and the routing handler @@ -2185,9 +2175,7 @@ mod unit_tests { routing_handler }, Message::ChannelUpdate(fake_channel_update_msg!()), - (| peer_manager: PeerManagerImpl>, mut descriptor | { - assert_matches!(peer_manager.read_event(&mut descriptor, &[]), Ok(_)); - } + (| _descriptor | { } )); // _____ _ _____ _ _ @@ -2271,13 +2259,13 @@ mod unit_tests { #[test] fn $test_name() { let channel_handler = TestChannelMessageHandler::new(); - channel_handler.pending_events.lock().unwrap().push($event); - - let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let test_ctx = TestCtx::<&TestChannelMessageHandler, RoutingMessageHandlerTestStub>::with_channel_handler(&channel_handler); let mut descriptor = SocketDescriptorMock::new(); let transport = new_connected_transport!(&test_ctx); let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + channel_handler.pending_events.lock().unwrap().push($event); + peer_manager.process_events(); let recording = descriptor.get_recording(); @@ -2402,6 +2390,11 @@ mod unit_tests { #[test] fn post_init_send_update_htlcs() { let channel_handler = TestChannelMessageHandler::new(); + let test_ctx = TestCtx::<&TestChannelMessageHandler, RoutingMessageHandlerTestStub>::with_channel_handler(&channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + channel_handler.pending_events.lock().unwrap().push(UpdateHTLCs { node_id: test_ctx_their_node_id!(), updates: CommitmentUpdate { @@ -2414,11 +2407,6 @@ mod unit_tests { } }); - let test_ctx = TestCtx::::with_channel_handler(channel_handler); - let mut descriptor = SocketDescriptorMock::new(); - let transport = new_connected_transport!(&test_ctx); - let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); - peer_manager.process_events(); let recording = descriptor.get_recording(); @@ -2641,16 +2629,16 @@ mod unit_tests { #[test] fn post_init_broadcast_channel_announcement() { let channel_handler = TestChannelMessageHandler::new(); + let test_ctx = TestCtx::<&TestChannelMessageHandler, RoutingMessageHandlerTestStub>::with_channel_handler(&channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelAnnouncement { msg: fake_channel_announcement_msg!(0, fake_public_key!(), fake_public_key!()), update_msg: fake_channel_update_msg!() }); - let test_ctx = TestCtx::::with_channel_handler(channel_handler); - let mut descriptor = SocketDescriptorMock::new(); - let transport = new_connected_transport!(&test_ctx); - let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); - peer_manager.process_events(); let recording = descriptor.get_recording(); @@ -2706,15 +2694,15 @@ mod unit_tests { #[test] fn post_init_broadcast_node_announcement() { let channel_handler = TestChannelMessageHandler::new(); - channel_handler.pending_events.lock().unwrap().push(BroadcastNodeAnnouncement { - msg: fake_node_announcement_msg!() - }); - - let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let test_ctx = TestCtx::<&TestChannelMessageHandler, RoutingMessageHandlerTestStub>::with_channel_handler(&channel_handler); let mut descriptor = SocketDescriptorMock::new(); let transport = new_connected_transport!(&test_ctx); let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + channel_handler.pending_events.lock().unwrap().push(BroadcastNodeAnnouncement { + msg: fake_node_announcement_msg!() + }); + peer_manager.process_events(); let recording = descriptor.get_recording(); @@ -2770,15 +2758,15 @@ mod unit_tests { #[test] fn post_init_broadcast_channel_update() { let channel_handler = TestChannelMessageHandler::new(); - channel_handler.pending_events.lock().unwrap().push(BroadcastChannelUpdate { - msg: fake_channel_update_msg!() - }); - - let test_ctx = TestCtx::::with_channel_handler(channel_handler); + let test_ctx = TestCtx::<&TestChannelMessageHandler, RoutingMessageHandlerTestStub>::with_channel_handler(&channel_handler); let mut descriptor = SocketDescriptorMock::new(); let transport = new_connected_transport!(&test_ctx); let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + channel_handler.pending_events.lock().unwrap().push(BroadcastChannelUpdate { + msg: fake_channel_update_msg!() + }); + peer_manager.process_events(); let recording = descriptor.get_recording(); @@ -2862,6 +2850,11 @@ mod unit_tests { #[test] fn post_init_handle_error_event_disconnect_message() { let channel_handler = TestChannelMessageHandler::new(); + let test_ctx = TestCtx::<&TestChannelMessageHandler, RoutingMessageHandlerTestStub>::with_channel_handler(&channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + channel_handler.pending_events.lock().unwrap().push(HandleError { node_id: test_ctx_their_node_id!(), action: ErrorAction::DisconnectPeer { msg: Some(ErrorMessage { @@ -2870,11 +2863,6 @@ mod unit_tests { })} }); - let test_ctx = TestCtx::::with_channel_handler(channel_handler); - let mut descriptor = SocketDescriptorMock::new(); - let transport = new_connected_transport!(&test_ctx); - let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); - peer_manager.process_events(); let recording = descriptor.get_recording(); @@ -2911,6 +2899,11 @@ mod unit_tests { #[test] fn post_init_handle_error_event_send_error_message() { let channel_handler = TestChannelMessageHandler::new(); + let test_ctx = TestCtx::<&TestChannelMessageHandler, RoutingMessageHandlerTestStub>::with_channel_handler(&channel_handler); + let mut descriptor = SocketDescriptorMock::new(); + let transport = new_connected_transport!(&test_ctx); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); + channel_handler.pending_events.lock().unwrap().push(HandleError { node_id: test_ctx_their_node_id!(), action: ErrorAction::SendErrorMessage { @@ -2918,11 +2911,6 @@ mod unit_tests { } }); - let test_ctx = TestCtx::::with_channel_handler(channel_handler); - let mut descriptor = SocketDescriptorMock::new(); - let transport = new_connected_transport!(&test_ctx); - let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); - peer_manager.process_events(); let recording = descriptor.get_recording(); @@ -3144,15 +3132,20 @@ mod tests { let initial_data = peer_b.new_outbound_connection(a_id, fd_b.clone()).unwrap(); peer_a.new_inbound_connection(fd_a.clone()).unwrap(); assert_eq!(peer_a.read_event(&mut fd_a, &initial_data).unwrap(), false); + peer_a.process_events(); assert_eq!(peer_b.read_event(&mut fd_b, &fd_a.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); + peer_b.process_events(); assert_eq!(peer_a.read_event(&mut fd_a, &fd_b.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); + peer_a.process_events(); (fd_a.clone(), fd_b.clone()) } fn establish_connection_and_read_events<'a>(peer_a: &PeerManager, peer_b: &PeerManager) -> (FileDescriptor, FileDescriptor) { let (mut fd_a, mut fd_b) = establish_connection(peer_a, peer_b); assert_eq!(peer_b.read_event(&mut fd_b, &fd_a.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); + peer_b.process_events(); assert_eq!(peer_a.read_event(&mut fd_a, &fd_b.outbound_data.lock().unwrap().split_off(0)).unwrap(), false); + peer_a.process_events(); (fd_a.clone(), fd_b.clone()) } @@ -3215,7 +3208,9 @@ mod tests { // Make each peer to read the messages that the other peer just wrote to them. peers[1].read_event(&mut fd_b, &fd_a.outbound_data.lock().unwrap().split_off(0)).unwrap(); + peers[1].process_events(); peers[0].read_event(&mut fd_a, &fd_b.outbound_data.lock().unwrap().split_off(0)).unwrap(); + peers[0].process_events(); // Check that each peer has received the expected number of channel updates and channel // announcements. diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs index 8b9be9b8c89..20e36adf9b9 100644 --- a/lightning/src/util/test_utils.rs +++ b/lightning/src/util/test_utils.rs @@ -313,6 +313,91 @@ impl events::MessageSendEventsProvider for TestChannelMessageHandler { } } +// &TestChannelMessageHandler passthroughs so TypeParameters can be either a value or ref in test object containers +impl<'a> ChannelMessageHandler for &'a TestChannelMessageHandler { + fn handle_open_channel(&self, their_node_id: &PublicKey, their_features: InitFeatures, msg: &OpenChannel) { + TestChannelMessageHandler::handle_open_channel(self, their_node_id, their_features, msg); + } + + fn handle_accept_channel(&self, their_node_id: &PublicKey, their_features: InitFeatures, msg: &AcceptChannel) { + TestChannelMessageHandler::handle_accept_channel(self, their_node_id, their_features, msg); + } + + fn handle_funding_created(&self, their_node_id: &PublicKey, msg: &FundingCreated) { + TestChannelMessageHandler::handle_funding_created(self, their_node_id, msg); + } + + fn handle_funding_signed(&self, their_node_id: &PublicKey, msg: &FundingSigned) { + TestChannelMessageHandler::handle_funding_signed(self, their_node_id, msg); + } + + fn handle_funding_locked(&self, their_node_id: &PublicKey, msg: &FundingLocked) { + TestChannelMessageHandler::handle_funding_locked(self, their_node_id, msg); + } + + fn handle_shutdown(&self, their_node_id: &PublicKey, msg: &Shutdown) { + TestChannelMessageHandler::handle_shutdown(self, their_node_id, msg); + } + + fn handle_closing_signed(&self, their_node_id: &PublicKey, msg: &ClosingSigned) { + TestChannelMessageHandler::handle_closing_signed(self, their_node_id, msg); + } + + fn handle_update_add_htlc(&self, their_node_id: &PublicKey, msg: &UpdateAddHTLC) { + TestChannelMessageHandler::handle_update_add_htlc(self, their_node_id, msg); + } + + fn handle_update_fulfill_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFulfillHTLC) { + TestChannelMessageHandler::handle_update_fulfill_htlc(self, their_node_id, msg); + } + + fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailHTLC) { + TestChannelMessageHandler::handle_update_fail_htlc(self, their_node_id, msg); + } + + fn handle_update_fail_malformed_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailMalformedHTLC) { + TestChannelMessageHandler::handle_update_fail_malformed_htlc(self, their_node_id, msg); + } + + fn handle_commitment_signed(&self, their_node_id: &PublicKey, msg: &CommitmentSigned) { + TestChannelMessageHandler::handle_commitment_signed(self, their_node_id, msg); + } + + fn handle_revoke_and_ack(&self, their_node_id: &PublicKey, msg: &RevokeAndACK) { + TestChannelMessageHandler::handle_revoke_and_ack(self, their_node_id, msg); + } + + fn handle_update_fee(&self, their_node_id: &PublicKey, msg: &UpdateFee) { + TestChannelMessageHandler::handle_update_fee(self, their_node_id, msg); + } + + fn handle_announcement_signatures(&self, their_node_id: &PublicKey, msg: &AnnouncementSignatures) { + TestChannelMessageHandler::handle_announcement_signatures(self, their_node_id, msg); + } + + fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool) { + TestChannelMessageHandler::peer_disconnected(self, their_node_id, no_connection_possible); + } + + fn peer_connected(&self, their_node_id: &PublicKey, msg: &Init) { + TestChannelMessageHandler::peer_connected(self, their_node_id, msg); + } + + fn handle_channel_reestablish(&self, their_node_id: &PublicKey, msg: &ChannelReestablish) { + TestChannelMessageHandler::handle_channel_reestablish(self, their_node_id, msg); + } + + fn handle_error(&self, their_node_id: &PublicKey, msg: &ErrorMessage) { + TestChannelMessageHandler::handle_error(self, their_node_id, msg); + } +} + +impl<'a> events::MessageSendEventsProvider for &'a TestChannelMessageHandler { + fn get_and_clear_pending_msg_events(&self) -> Vec { + TestChannelMessageHandler::get_and_clear_pending_msg_events(self, ) + } +} + fn get_dummy_channel_announcement(short_chan_id: u64) -> msgs::ChannelAnnouncement { use bitcoin::secp256k1::ffi::Signature as FFISignature; let secp_ctx = Secp256k1::new(); From 75da46b40675c0b248acde5f2ed0e03d9b78ed22 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sat, 5 Sep 2020 16:36:23 -0700 Subject: [PATCH 80/96] refactor: Continue constricting interfaces in message queue path Introduce the MessageQueuer interface used by Transport to queue messages for send and use it in all the existing places where messages are queued. --- lightning/src/ln/peers/handler.rs | 118 +++++++++-------------- lightning/src/ln/peers/outbound_queue.rs | 3 +- lightning/src/ln/peers/test_util.rs | 8 +- lightning/src/ln/peers/transport.rs | 26 +++-- 4 files changed, 75 insertions(+), 80 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 83926c4c82c..c6faad3d132 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -30,12 +30,12 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::hashes::sha256::HashEngine as Sha256Engine; use bitcoin::hashes::{HashEngine, Hash}; use ln::peers::outbound_queue::OutboundQueue; -use ln::peers::transport::Transport; +use ln::peers::transport::{PayloadQueuer, Transport}; const MSG_BUFF_SIZE: usize = 10; -/// Interface PeerHandler uses to interact with the Transport object -pub(super) trait ITransport { +/// Interface PeerManager uses to interact with the Transport object +pub(super) trait ITransport: MessageQueuer { /// Instantiate the new outbound Transport fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self; @@ -56,41 +56,16 @@ pub(super) trait ITransport { /// Returns all Messages that have been received and can be parsed by the Transport fn drain_messages(&mut self, logger: L) -> Result, PeerHandleError> where L::Target: Logger; +} +/// Interface PeerManager uses to queue message to send. Used primarily to restrict the interface in +/// specific contexts. e.g. Only queueing during read_event(). No flushing allowed. +pub(super) trait MessageQueuer { /// Encodes, encrypts, and enqueues a message to the outbound queue. Panics if the connection is /// not established yet. fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, logger: L) where L::Target: Logger; } - -/// Trait representing a container that allows enqueuing of Vec<[u8]> -pub(super) trait PayloadQueuer { - /// Enqueue item to the queue - fn push_back(&mut self, item: Vec); - - /// Returns true if the queue is empty - fn is_empty(&self) -> bool; - - /// Returns the amount of available space in queue - fn queue_space(&self) -> usize; -} - -/// Implement &mut PayloadQueuer passthroughs -impl<'a, T> PayloadQueuer for &'a mut T where - T: PayloadQueuer { - fn push_back(&mut self, item: Vec) { - T::push_back(self, item) - } - - fn is_empty(&self) -> bool { - T::is_empty(self) - } - - fn queue_space(&self) -> usize { - T::queue_space(self) - } -} - /// Trait representing a container that can try to flush data through a SocketDescriptor pub(super) trait SocketDescriptorFlusher { /// Write previously enqueued data to the SocketDescriptor. A return of false indicates the @@ -511,10 +486,10 @@ impl( &self, - descriptor: &mut Descriptor, - sync_status: &mut InitSyncTracker, - transport: &mut impl ITransport, - pending_outbound_buffer: &mut Q) { + descriptor: &mut Descriptor, + sync_status: &mut InitSyncTracker, + message_queuer: &mut impl MessageQueuer, + pending_outbound_buffer: &mut Q) { while !pending_outbound_buffer.is_blocked() { let queue_space = pending_outbound_buffer.queue_space(); if queue_space > 0 { @@ -524,12 +499,12 @@ impl(&self, peers_needing_send: &mut HashSet, transport: &mut impl ITransport, output_buffer: &mut impl PayloadQueuer, descriptor: &Descriptor, message: &M) { - transport.enqueue_message(message, output_buffer, &*self.logger); + fn enqueue_message(&self, peers_needing_send: &mut HashSet, message_queuer: &mut impl MessageQueuer, output_buffer: &mut impl PayloadQueuer, descriptor: &Descriptor, message: &M) { + message_queuer.enqueue_message(message, output_buffer, &*self.logger); peers_needing_send.insert(descriptor.clone()); } @@ -696,7 +671,7 @@ impl { return Err(e) }, MessageHandlingError::LightningError(e) => { @@ -721,15 +696,16 @@ impl, - transport: &mut impl ITransport, + their_node_id: PublicKey, + message_queuer: &mut impl MessageQueuer, pending_outbound_buffer: &mut impl PayloadQueuer ) -> Result<(), MessageHandlingError> { - log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(transport.get_their_node_id())); + log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(&their_node_id)); // Need an Init as first message if let wire::Message::Init(_) = message { } else if their_features.is_none() { - log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(transport.get_their_node_id())); + log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(&their_node_id)); return Err(PeerHandleError{ no_connection_possible: false }.into()); } @@ -762,21 +738,21 @@ impl { @@ -789,11 +765,11 @@ impl { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; - self.enqueue_message(peers_needing_send, transport, pending_outbound_buffer, &peer_descriptor, &resp); + self.enqueue_message(peers_needing_send, message_queuer, pending_outbound_buffer, &peer_descriptor, &resp); } }, wire::Message::Pong(_msg) => { @@ -811,59 +787,59 @@ impl { - self.message_handler.chan_handler.handle_open_channel(&transport.get_their_node_id(), their_features.clone().unwrap(), &msg); + self.message_handler.chan_handler.handle_open_channel(&their_node_id, their_features.clone().unwrap(), &msg); }, wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&transport.get_their_node_id(), their_features.clone().unwrap(), &msg); + self.message_handler.chan_handler.handle_accept_channel(&their_node_id, their_features.clone().unwrap(), &msg); }, wire::Message::FundingCreated(msg) => { - self.message_handler.chan_handler.handle_funding_created(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_funding_created(&their_node_id, &msg); }, wire::Message::FundingSigned(msg) => { - self.message_handler.chan_handler.handle_funding_signed(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_funding_signed(&their_node_id, &msg); }, wire::Message::FundingLocked(msg) => { - self.message_handler.chan_handler.handle_funding_locked(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_funding_locked(&their_node_id, &msg); }, wire::Message::Shutdown(msg) => { - self.message_handler.chan_handler.handle_shutdown(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_shutdown(&their_node_id, &msg); }, wire::Message::ClosingSigned(msg) => { - self.message_handler.chan_handler.handle_closing_signed(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_closing_signed(&their_node_id, &msg); }, // Commitment messages: wire::Message::UpdateAddHTLC(msg) => { - self.message_handler.chan_handler.handle_update_add_htlc(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_add_htlc(&their_node_id, &msg); }, wire::Message::UpdateFulfillHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fulfill_htlc(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fulfill_htlc(&their_node_id, &msg); }, wire::Message::UpdateFailHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_htlc(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fail_htlc(&their_node_id, &msg); }, wire::Message::UpdateFailMalformedHTLC(msg) => { - self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fail_malformed_htlc(&their_node_id, &msg); }, wire::Message::CommitmentSigned(msg) => { - self.message_handler.chan_handler.handle_commitment_signed(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_commitment_signed(&their_node_id, &msg); }, wire::Message::RevokeAndACK(msg) => { - self.message_handler.chan_handler.handle_revoke_and_ack(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_revoke_and_ack(&their_node_id, &msg); }, wire::Message::UpdateFee(msg) => { - self.message_handler.chan_handler.handle_update_fee(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_update_fee(&their_node_id, &msg); }, wire::Message::ChannelReestablish(msg) => { - self.message_handler.chan_handler.handle_channel_reestablish(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_channel_reestablish(&their_node_id, &msg); }, // Routing messages: wire::Message::AnnouncementSignatures(msg) => { - self.message_handler.chan_handler.handle_announcement_signatures(&transport.get_their_node_id(), &msg); + self.message_handler.chan_handler.handle_announcement_signatures(&their_node_id, &msg); }, wire::Message::ChannelAnnouncement(msg) => { let should_forward = match self.message_handler.route_handler.handle_channel_announcement(&msg) { diff --git a/lightning/src/ln/peers/outbound_queue.rs b/lightning/src/ln/peers/outbound_queue.rs index 501a4756524..fa9b1258bd4 100644 --- a/lightning/src/ln/peers/outbound_queue.rs +++ b/lightning/src/ln/peers/outbound_queue.rs @@ -1,7 +1,8 @@ /// Abstracts the buffer used to write data through a SocketDescriptor handling partial writes and /// flow control. -use ln::peers::handler::{SocketDescriptor, PayloadQueuer, SocketDescriptorFlusher}; +use ln::peers::handler::{SocketDescriptor, SocketDescriptorFlusher}; +use ln::peers::transport::PayloadQueuer; use std::collections::LinkedList; use std::cmp; diff --git a/lightning/src/ln/peers/test_util.rs b/lightning/src/ln/peers/test_util.rs index f2f39fe82cd..34330d5c0b1 100644 --- a/lightning/src/ln/peers/test_util.rs +++ b/lightning/src/ln/peers/test_util.rs @@ -4,8 +4,8 @@ use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use ln::peers::conduit::Conduit; -use ln::peers::handler::{SocketDescriptor, PayloadQueuer, ITransport, PeerHandleError}; -use ln::peers::transport::IPeerHandshake; +use ln::peers::handler::{SocketDescriptor, ITransport, PeerHandleError, MessageQueuer}; +use ln::peers::transport::{IPeerHandshake, PayloadQueuer}; use std::rc::Rc; use std::cell::{RefCell}; @@ -300,7 +300,9 @@ impl<'a> ITransport for &'a RefCell { fn drain_messages(&mut self, logger: L) -> Result, PeerHandleError> where L::Target: Logger { self.borrow_mut().drain_messages(logger) } +} +impl<'a> MessageQueuer for &'a RefCell { fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, logger: L) where L::Target: Logger { self.borrow_mut().enqueue_message(message, output_buffer, logger) } @@ -351,7 +353,9 @@ impl ITransport for TransportStub { fn drain_messages(&mut self, _logger: L) -> Result, PeerHandleError> where L::Target: Logger { Ok(self.messages.drain(..).collect()) } +} +impl MessageQueuer for TransportStub { fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, _logger: L) where L::Target: Logger { let mut buffer = VecWriter(Vec::new()); diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index 40362f9acad..0805148f203 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -3,7 +3,7 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::conduit::Conduit; -use ln::peers::handler::{ITransport, PeerHandleError, PayloadQueuer}; +use ln::peers::handler::{ITransport, PeerHandleError, MessageQueuer}; use ln::peers::handshake::PeerHandshake; use ln::{wire, msgs}; use ln::wire::{Encode, Message}; @@ -28,6 +28,18 @@ pub trait IPeerHandshake { fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String>; } +/// Trait representing a container that allows enqueuing of Vec<[u8]> +pub(super) trait PayloadQueuer { + /// Enqueue item to the queue + fn push_back(&mut self, item: Vec); + + /// Returns true if the queue is empty + fn is_empty(&self) -> bool; + + /// Returns the amount of available space in queue + fn queue_space(&self) -> usize; +} + pub(super) struct Transport { pub(super) conduit: Option, handshake: PeerHandshakeImpl, @@ -146,6 +158,13 @@ impl ITransport for Transport PublicKey { + assert!(self.is_connected(), "Retrieving the remote node_id is only supported after transport is connected"); + self.their_node_id.unwrap() + } +} + +impl MessageQueuer for Transport { fn enqueue_message(&mut self, message: &M, output_buffer: &mut Q, logger: L) where L::Target: Logger { @@ -160,11 +179,6 @@ impl ITransport for Transport PublicKey { - assert!(self.is_connected(), "Retrieving the remote node_id is only supported after transport is connected"); - self.their_node_id.unwrap() - } } #[cfg(test)] From 1cf81e5a9c73194f3abdb201f67b0dc296bd8726 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Sat, 5 Sep 2020 17:49:06 -0700 Subject: [PATCH 81/96] refactor: Clean up event handling path w.r.t connected state Many of the is_connected() checks were duplicative due to the macro continuing out of the match statement if the peer referenced by the node_id had not seen an Init message yet. Remove the macro in favor of a function on PeerHolder that will return an Option<> and use it instead. Split out a new helper function Peer::is_initialized() that will return true if the peer has seen an Init message. --- lightning/src/ln/peers/handler.rs | 190 ++++++++++++++---------------- 1 file changed, 90 insertions(+), 100 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index c6faad3d132..0202b4edd29 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -172,6 +172,13 @@ struct Peer { } impl Peer { + + /// Returns true if an INIT message has been received from this peer. Implies that this node + /// can send and receive encrypted messages. + fn is_initialized(&self) -> bool { + self.their_features.is_some() + } + /// Returns true if the channel announcements/updates for the given channel should be /// forwarded to this peer. /// If we are sending our routing table to this peer and we have not yet sent channel @@ -205,6 +212,30 @@ struct PeerHolder { node_id_to_descriptor: HashMap, } +impl PeerHolder { + fn initialized_peer_by_node_id(&mut self, node_id: &PublicKey) -> Option<(Descriptor, &mut Peer)> { + match self.node_id_to_descriptor.get_mut(node_id) { + None => None, + Some(descriptor) => { + assert!(self.peers.contains_key(descriptor), "Invalid PeerHolder state"); + + match self.peers.get_mut(&descriptor) { + None => panic!("Invalid PeerHolder state!"), + Some(peer) => { + + // their_features is set after receiving an Init message + if !peer.is_initialized() { + None + } else { + Some((descriptor.clone(), peer)) + } + } + } + } + } + } +} + #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] fn _check_usize_is_32_or_64() { // See below, less than 32 bit pointers may be unsafe here! @@ -416,7 +447,7 @@ impl Vec { let peers = self.peers.lock().unwrap(); peers.peers.values().filter_map(|p| { - if !p.transport.is_connected() || p.their_features.is_none() { + if !p.is_initialized() { return None; } Some(p.transport.get_their_node_id()) @@ -895,105 +926,76 @@ impl { - { - let descriptor = match peers.node_id_to_descriptor.get($node_id) { - Some(descriptor) => descriptor.clone(), - None => { - $handle_no_such_peer; - continue; - }, - }; - match peers.peers.get_mut(&descriptor) { - Some(peer) => { - if peer.their_features.is_none() { - $handle_no_such_peer; - continue; - } - (descriptor, peer) - }, - None => panic!("Inconsistent peers set state!"), - } - } - } - } match event { MessageSendEvent::SendAcceptChannel { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendAcceptChannel event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.temporary_channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: Drop the pending channel? (or just let it timeout, but that sucks) - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: Drop the pending channel? (or just let it timeout, but that sucks) } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendOpenChannel { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendOpenChannel event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.temporary_channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: Drop the pending channel? (or just let it timeout, but that sucks) - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: Drop the pending channel? (or just let it timeout, but that sucks) } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendFundingCreated { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendFundingCreated event in peer_handler for node {} for channel {} (which becomes {})", log_pubkey!(node_id), log_bytes!(msg.temporary_channel_id), log_funding_channel_id!(msg.funding_txid, msg.funding_output_index)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: generate a DiscardFunding event indicating to the wallet that - //they should just throw away this funding transaction - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: generate a DiscardFunding event indicating to the wallet that + //they should just throw away this funding transaction } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendFundingSigned { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendFundingSigned event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: generate a DiscardFunding event indicating to the wallet that - //they should just throw away this funding transaction - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: generate a DiscardFunding event indicating to the wallet that + //they should just throw away this funding transaction } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendFundingLocked { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendFundingLocked event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: Do whatever we're gonna do for handling dropped messages - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: Do whatever we're gonna do for handling dropped messages } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendAnnouncementSignatures event in peer_handler for node {} for channel {})", log_pubkey!(node_id), log_bytes!(msg.channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: generate a DiscardFunding event indicating to the wallet that - //they should just throw away this funding transaction - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: generate a DiscardFunding event indicating to the wallet that + //they should just throw away this funding transaction } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => { log_trace!(self.logger, "Handling UpdateHTLCs event in peer_handler for node {} with {} adds, {} fulfills, {} fails for channel {}", @@ -1002,10 +1004,7 @@ impl { log_trace!(self.logger, "Handling SendRevokeAndACK event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: Do whatever we're gonna do for handling dropped messages - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: Do whatever we're gonna do for handling dropped messages } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendClosingSigned { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendClosingSigned event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: Do whatever we're gonna do for handling dropped messages - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: Do whatever we're gonna do for handling dropped messages } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendShutdown { ref node_id, ref msg } => { log_trace!(self.logger, "Handling Shutdown event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: Do whatever we're gonna do for handling dropped messages - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: Do whatever we're gonna do for handling dropped messages } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => { log_trace!(self.logger, "Handling SendChannelReestablish event in peer_handler for node {} for channel {}", log_pubkey!(node_id), log_bytes!(msg.channel_id)); - let (mut descriptor, peer) = get_peer_for_forwarding!(node_id, { - //TODO: Do whatever we're gonna do for handling dropped messages - }); - if peer.transport.is_connected() { + if let Some((mut descriptor, peer)) = peers.initialized_peer_by_node_id(node_id) { peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + } else { + //TODO: Do whatever we're gonna do for handling dropped messages } - self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); }, MessageSendEvent::BroadcastChannelAnnouncement { ref msg, ref update_msg } => { log_trace!(self.logger, "Handling BroadcastChannelAnnouncement event in peer_handler for short channel id {}", msg.contents.short_channel_id); if self.message_handler.route_handler.handle_channel_announcement(msg).is_ok() && self.message_handler.route_handler.handle_channel_update(update_msg).is_ok() { for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.transport.is_connected() || peer.their_features.is_none() || + if !peer.is_initialized() || !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { continue } @@ -1086,10 +1083,8 @@ impl Date: Mon, 7 Sep 2020 15:45:51 -0700 Subject: [PATCH 82/96] refactor: Introduce PostInitState Encapsulate the Peer information that is only valid after an Init message has been seen. This makes the accesses to sync_status, ping information, and their_features cleaner w.r.t. the Peer initialization state. --- lightning/src/ln/peers/handler.rs | 348 +++++++++++++++++------------- 1 file changed, 198 insertions(+), 150 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 0202b4edd29..39b0ba2d4fc 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -159,24 +159,44 @@ enum InitSyncTracker{ NodesSyncing(PublicKey), } +// Container for all state only valid after an Init message is seen +struct PostInitState { + awaiting_pong: bool, + sync_status: InitSyncTracker, + their_features: InitFeatures, +} + +impl PostInitState { + fn new(sync_status: InitSyncTracker, their_features: InitFeatures) -> Self { + Self { + awaiting_pong: false, + sync_status, + their_features + } + } +} + struct Peer { - transport: TransportImpl, outbound: bool, - their_features: Option, - pending_outbound_buffer: OutboundQueue, - - sync_status: InitSyncTracker, - - awaiting_pong: bool, + post_init_state: Option, + transport: TransportImpl, } impl Peer { + fn new(outbound: bool, transport: TransportImpl) -> Self { + Self { + outbound, + pending_outbound_buffer: OutboundQueue::new(MSG_BUFF_SIZE), + post_init_state: None, + transport + } + } /// Returns true if an INIT message has been received from this peer. Implies that this node /// can send and receive encrypted messages. fn is_initialized(&self) -> bool { - self.their_features.is_some() + self.post_init_state.is_some() } /// Returns true if the channel announcements/updates for the given channel should be @@ -185,20 +205,30 @@ impl Peer { /// announcements/updates for the given channel_id then we will send it when we get to that /// point and we shouldn't send it yet to avoid sending duplicate updates. If we've already /// sent the old versions, we should send the update, and so return true here. - fn should_forward_channel_announcement(&self, channel_id: u64)->bool{ - match self.sync_status { - InitSyncTracker::NoSyncRequested => true, - InitSyncTracker::ChannelsSyncing(i) => i < channel_id, - InitSyncTracker::NodesSyncing(_) => true, + fn should_forward_channel_announcement(&self, channel_id: u64) -> bool{ + match &self.post_init_state { + None => panic!("should_forward_channel_announcement() only valid on an uninitialized peer"), + Some(state) => { + match state.sync_status { + InitSyncTracker::NoSyncRequested => true, + InitSyncTracker::ChannelsSyncing(i) => i < channel_id, + InitSyncTracker::NodesSyncing(_) => true, + } + } } } /// Similar to the above, but for node announcements indexed by node_id. fn should_forward_node_announcement(&self, node_id: PublicKey) -> bool { - match self.sync_status { - InitSyncTracker::NoSyncRequested => true, - InitSyncTracker::ChannelsSyncing(_) => false, - InitSyncTracker::NodesSyncing(pk) => pk < node_id, + match &self.post_init_state { + None => panic!("should_forward_channel_announcement() only valid on an uninitialized peer"), + Some(state) => { + match state.sync_status { + InitSyncTracker::NoSyncRequested => true, + InitSyncTracker::ChannelsSyncing(_) => false, + InitSyncTracker::NodesSyncing(pk) => pk < node_id, + } + } } } } @@ -476,17 +506,7 @@ impl { - transport, - outbound: true, - their_features: None, - - pending_outbound_buffer: OutboundQueue::new(MSG_BUFF_SIZE), - - sync_status: InitSyncTracker::NoSyncRequested, - - awaiting_pong: false, - }).is_some() { + if peers.peers.insert(descriptor, Peer::::new(true, transport)).is_some() { panic!("PeerManager driver duplicated descriptors!"); }; Ok(initial_bytes) @@ -499,74 +519,80 @@ impl Result<(), PeerHandleError> { let mut peers = self.peers.lock().unwrap(); - if peers.peers.insert(descriptor, Peer:: { - transport, - outbound: false, - their_features: None, - - pending_outbound_buffer: OutboundQueue::new(MSG_BUFF_SIZE), - - sync_status: InitSyncTracker::NoSyncRequested, - - awaiting_pong: false, - }).is_some() { + if peers.peers.insert(descriptor, Peer::::new(false, transport)).is_some() { panic!("PeerManager driver duplicated descriptors!"); }; Ok(()) } - fn do_attempt_write_data( + // Fill remaining slots in output queue with sync messages, updating the sync state when + // appropriate + fn fill_message_queue_with_sync( &self, - descriptor: &mut Descriptor, sync_status: &mut InitSyncTracker, message_queuer: &mut impl MessageQueuer, pending_outbound_buffer: &mut Q) { - while !pending_outbound_buffer.is_blocked() { - let queue_space = pending_outbound_buffer.queue_space(); - if queue_space > 0 { - match sync_status { - &mut InitSyncTracker::NoSyncRequested => {}, - &mut InitSyncTracker::ChannelsSyncing(c) if c < 0xffff_ffff_ffff_ffff => { - let steps = ((queue_space + 2) / 3) as u8; - let all_messages = self.message_handler.route_handler.get_next_channel_announcements(c, steps); - for &(ref announce, ref update_a_option, ref update_b_option) in all_messages.iter() { - message_queuer.enqueue_message(announce, pending_outbound_buffer, &*self.logger); - if let &Some(ref update_a) = update_a_option { - message_queuer.enqueue_message(update_a, pending_outbound_buffer, &*self.logger); - } - if let &Some(ref update_b) = update_b_option { - message_queuer.enqueue_message(update_b, pending_outbound_buffer, &*self.logger); - } - *sync_status = InitSyncTracker::ChannelsSyncing(announce.contents.short_channel_id + 1); - } - if all_messages.is_empty() || all_messages.len() != steps as usize { - *sync_status = InitSyncTracker::ChannelsSyncing(0xffff_ffff_ffff_ffff); - } - }, - &mut InitSyncTracker::ChannelsSyncing(c) if c == 0xffff_ffff_ffff_ffff => { - let steps = queue_space as u8; - let all_messages = self.message_handler.route_handler.get_next_node_announcements(None, steps); - for msg in all_messages.iter() { - message_queuer.enqueue_message(msg, pending_outbound_buffer, &*self.logger); - *sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); - } - if all_messages.is_empty() || all_messages.len() != steps as usize { - *sync_status = InitSyncTracker::NoSyncRequested; - } - }, - &mut InitSyncTracker::ChannelsSyncing(_) => unreachable!(), - &mut InitSyncTracker::NodesSyncing(key) => { - let steps = queue_space as u8; - let all_messages = self.message_handler.route_handler.get_next_node_announcements(Some(&key), steps); - for msg in all_messages.iter() { - message_queuer.enqueue_message(msg, pending_outbound_buffer, &*self.logger); - *sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); + + let queue_space = pending_outbound_buffer.queue_space(); + if queue_space > 0 { + match sync_status { + &mut InitSyncTracker::NoSyncRequested => {}, + &mut InitSyncTracker::ChannelsSyncing(c) if c < 0xffff_ffff_ffff_ffff => { + let steps = ((queue_space + 2) / 3) as u8; + let all_messages = self.message_handler.route_handler.get_next_channel_announcements(c, steps); + for &(ref announce, ref update_a_option, ref update_b_option) in all_messages.iter() { + message_queuer.enqueue_message(announce, pending_outbound_buffer, &*self.logger); + if let &Some(ref update_a) = update_a_option { + message_queuer.enqueue_message(update_a, pending_outbound_buffer, &*self.logger); } - if all_messages.is_empty() || all_messages.len() != steps as usize { - *sync_status = InitSyncTracker::NoSyncRequested; + if let &Some(ref update_b) = update_b_option { + message_queuer.enqueue_message(update_b, pending_outbound_buffer, &*self.logger); } - }, - } + *sync_status = InitSyncTracker::ChannelsSyncing(announce.contents.short_channel_id + 1); + } + if all_messages.is_empty() || all_messages.len() != steps as usize { + *sync_status = InitSyncTracker::ChannelsSyncing(0xffff_ffff_ffff_ffff); + } + }, + &mut InitSyncTracker::ChannelsSyncing(c) if c == 0xffff_ffff_ffff_ffff => { + let steps = queue_space as u8; + let all_messages = self.message_handler.route_handler.get_next_node_announcements(None, steps); + for msg in all_messages.iter() { + message_queuer.enqueue_message(msg, pending_outbound_buffer, &*self.logger); + *sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); + } + if all_messages.is_empty() || all_messages.len() != steps as usize { + *sync_status = InitSyncTracker::NoSyncRequested; + } + }, + &mut InitSyncTracker::ChannelsSyncing(_) => unreachable!(), + &mut InitSyncTracker::NodesSyncing(key) => { + let steps = queue_space as u8; + let all_messages = self.message_handler.route_handler.get_next_node_announcements(Some(&key), steps); + for msg in all_messages.iter() { + message_queuer.enqueue_message(msg, pending_outbound_buffer, &*self.logger); + *sync_status = InitSyncTracker::NodesSyncing(msg.contents.node_id); + } + if all_messages.is_empty() || all_messages.len() != steps as usize { + *sync_status = InitSyncTracker::NoSyncRequested; + } + }, + } + } + } + + fn do_attempt_write_data( + &self, + descriptor: &mut Descriptor, + post_init_state: &mut Option, + message_queuer: &mut impl MessageQueuer, + pending_outbound_buffer: &mut Q) { + + while !pending_outbound_buffer.is_blocked() { + // If connected, fill output queue with sync messages + match post_init_state { + None => {}, + &mut Some(ref mut state) => self.fill_message_queue_with_sync(&mut state.sync_status, message_queuer, pending_outbound_buffer) } // No messages to send @@ -584,7 +610,7 @@ impl panic!("Descriptor for write_event is not already known to PeerManager"), Some(peer) => { peer.pending_outbound_buffer.unblock(); - self.do_attempt_write_data(descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + self.do_attempt_write_data(descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); } }; Ok(()) @@ -597,7 +623,7 @@ impl panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => peer }; - self.do_read_event(peer_descriptor, data, peer.outbound, &mut peer.sync_status, &mut peer.awaiting_pong, &mut peer.their_features, &mut peer.transport, &mut peer.pending_outbound_buffer, &mut peers.node_id_to_descriptor, &mut peers.peers_needing_send) + self.do_read_event(peer_descriptor, data, peer.outbound, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer, &mut peers.node_id_to_descriptor, &mut peers.peers_needing_send) }; match result { @@ -619,9 +645,7 @@ impl, + post_init_state: &mut Option, transport: &mut impl ITransport, pending_outbound_buffer: &mut impl PayloadQueuer, node_id_to_descriptor: &mut HashMap, @@ -702,7 +726,7 @@ impl { return Err(e) }, MessageHandlingError::LightningError(e) => { @@ -724,9 +748,7 @@ impl, + post_init_state: &mut Option, their_node_id: PublicKey, message_queuer: &mut impl MessageQueuer, pending_outbound_buffer: &mut impl PayloadQueuer @@ -735,7 +757,7 @@ impl { let mut data_is_printable = true; @@ -813,15 +840,29 @@ impl { - *awaiting_pong = false; + if let Some(ref mut state) = post_init_state { + state.awaiting_pong = false; + } else { + panic!("Received Pong before Init and didn't catch it earlier!"); + } }, // Channel messages: wire::Message::OpenChannel(msg) => { - self.message_handler.chan_handler.handle_open_channel(&their_node_id, their_features.clone().unwrap(), &msg); + match post_init_state { + None => panic!("Received OpenChannel before Init and didn't catch it earlier!"), + Some(state) => { + self.message_handler.chan_handler.handle_open_channel(&their_node_id, state.their_features.clone(), &msg); + } + } }, wire::Message::AcceptChannel(msg) => { - self.message_handler.chan_handler.handle_accept_channel(&their_node_id, their_features.clone().unwrap(), &msg); + match post_init_state { + None => panic!("Received AcceptChannel before Init and didn't catch it earlier!"), + Some(state) => { + self.message_handler.chan_handler.handle_accept_channel(&their_node_id, state.their_features.clone(), &msg); + } + } }, wire::Message::FundingCreated(msg) => { @@ -933,7 +974,7 @@ impl self.do_attempt_write_data(&mut descriptor, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer), + Some(peer) => self.do_attempt_write_data(&mut descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer), None => panic!("Inconsistent peers set state!"), } } @@ -1205,34 +1246,41 @@ impl return true, // retain + Some(ref mut post_init_state) => { + if post_init_state.awaiting_pong { + peers_needing_send.remove(descriptor); + descriptors_needing_disconnect.push(descriptor.clone()); + let their_node_id = peer.transport.get_their_node_id(); + log_trace!(self.logger, "Disconnecting peer with id {} due to ping timeout", their_node_id); + node_id_to_descriptor.remove(&their_node_id); + self.message_handler.chan_handler.peer_disconnected(&their_node_id, false); + + return false; // retain + } - let mut needs_to_write_data = false; - if peer.transport.is_connected() { - let ping = msgs::Ping { - ponglen: 0, - byteslen: 64, - }; - peer.transport.enqueue_message(&ping, &mut peer.pending_outbound_buffer, &*self.logger); - needs_to_write_data = true; - } + if peer.transport.is_connected() { + let ping = msgs::Ping { + ponglen: 0, + byteslen: 64, + }; + peer.transport.enqueue_message(&ping, &mut peer.pending_outbound_buffer, &*self.logger); + post_init_state.awaiting_pong = true; + + true // needs_to_write_data + } else { + false // !needs_to_write_data + } + } + }; if needs_to_write_data { let mut descriptor_clone = descriptor.clone(); - self.do_attempt_write_data(&mut descriptor_clone, &mut peer.sync_status, &mut peer.transport, &mut peer.pending_outbound_buffer); + self.do_attempt_write_data(&mut descriptor_clone, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); } - peer.awaiting_pong = true; - true + true // retain }); for mut descriptor in descriptors_needing_disconnect.drain(..) { @@ -3198,11 +3246,11 @@ mod tests { let peer_0 = peers[0].inner.peers.lock().unwrap(); let peer_1 = peers[1].inner.peers.lock().unwrap(); - let peer_0_features = peer_1.peers.get(&fd_1_to_0).unwrap().their_features.as_ref(); - let peer_1_features = peer_0.peers.get(&fd_0_to_1).unwrap().their_features.as_ref(); + let peer_0_features = peer_1.peers.get(&fd_1_to_0).unwrap().post_init_state.as_ref().unwrap(); + let peer_1_features = peer_0.peers.get(&fd_0_to_1).unwrap().post_init_state.as_ref().unwrap(); - assert!(peer_0_features.unwrap().initial_routing_sync()); - assert!(!peer_1_features.unwrap().initial_routing_sync()); + assert!(peer_0_features.their_features.initial_routing_sync()); + assert!(!peer_1_features.their_features.initial_routing_sync()); } // Outbound peer 1 requests initial_routing_sync, but inbound peer 0 does not. @@ -3215,11 +3263,11 @@ mod tests { let peer_0 = peers[0].inner.peers.lock().unwrap(); let peer_1 = peers[1].inner.peers.lock().unwrap(); - let peer_0_features = peer_1.peers.get(&fd_1_to_0).unwrap().their_features.as_ref(); - let peer_1_features = peer_0.peers.get(&fd_0_to_1).unwrap().their_features.as_ref(); + let peer_0_features = peer_1.peers.get(&fd_1_to_0).unwrap().post_init_state.as_ref().unwrap(); + let peer_1_features = peer_0.peers.get(&fd_0_to_1).unwrap().post_init_state.as_ref().unwrap(); - assert!(!peer_0_features.unwrap().initial_routing_sync()); - assert!(peer_1_features.unwrap().initial_routing_sync()); + assert!(!peer_0_features.their_features.initial_routing_sync()); + assert!(peer_1_features.their_features.initial_routing_sync()); } } } From b395e5f8f6951e8d7d57aa5a819f2756ce6452ff Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 7 Sep 2020 17:58:22 -0700 Subject: [PATCH 83/96] fix: Don't allow peer_disconnect before peer_connected callbacks The previous implementation would send a peer_disconnect callback for any error after the NOISE handshake completed, but only send a peer_connected callback after the Init message was received. This could lead to a dangling peer_disconnected callback that didn't have a paired peer_connected. This patch cleans up the state differentiation to match the following cases: unconnected (!transport.is_connected() && peer.post_init_info.is_none()) * Know about the peer, but are still in the process of the NOISE handshake connected (transport.is_connected() && peer.post_init_info.is_none()) * NOISE handshake completed, but haven't received an Init message initialized (transport.is_connected() && peer.post_init_info.is_some()) * The NOISE handshake has completed and the Init message has been received and processed With the 3 conceptual states, the read_event() path now only inserts a Peer into the node_id_to_descriptor map after a Peer enters the initialized state. This fixes the asymmetry between peer_disconnected & peer_connected as well as simplifies the disconnect code. --- lightning/src/ln/peers/handler.rs | 257 +++++++++++++++------------- lightning/src/ln/peers/test_util.rs | 16 +- lightning/src/ln/peers/transport.rs | 26 +-- 3 files changed, 162 insertions(+), 137 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 39b0ba2d4fc..920cf724f82 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -20,7 +20,7 @@ use util::events::{MessageSendEvent, MessageSendEventsProvider}; use util::logger::Logger; use routing::network_graph::NetGraphMsgHandler; -use std::collections::{HashMap,hash_map,HashSet}; +use std::collections::{HashMap,HashSet}; use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{cmp,error,hash,fmt}; @@ -46,7 +46,7 @@ pub(super) trait ITransport: MessageQueuer { fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self; /// Process input data similar to reading it off a descriptor directly. - fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result<(), String>; + fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result; /// Returns true if the connection is established and encrypted messages can be sent. fn is_connected(&self) -> bool; @@ -238,7 +238,7 @@ struct PeerHolder { /// Added to by do_read_event for cases where we pushed a message onto the send buffer but /// didn't call do_attempt_write_data to avoid reentrancy. Cleared in process_events() peers_needing_send: HashSet, - /// Only add to this set when noise completes: + /// Peers in this map have completed the NOISE handshake and received an Init message node_id_to_descriptor: HashMap, } @@ -641,6 +641,85 @@ impl Result { + if init_message.features.requires_unknown_bits() { + log_info!(self.logger, "Peer global features required unknown version bits"); + return Err(PeerHandleError { no_connection_possible: true }.into()); + } + if init_message.features.requires_unknown_bits() { + log_info!(self.logger, "Peer local features required unknown version bits"); + return Err(PeerHandleError { no_connection_possible: true }.into()); + } + + log_info!( + self.logger, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, static_remote_key: {}, unknown flags (local and global): {}", + if init_message.features.supports_data_loss_protect() { "supported" } else { "not supported"}, + if init_message.features.initial_routing_sync() { "requested" } else { "not requested" }, + if init_message.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, + if init_message.features.supports_static_remote_key() { "supported" } else { "not supported"}, + if init_message.features.supports_unknown_bits() { "present" } else { "none" } + ); + + let sync_status = if init_message.features.initial_routing_sync() { + InitSyncTracker::ChannelsSyncing(0) + } else { + InitSyncTracker::NoSyncRequested + }; + + if !init_message.features.supports_static_remote_key() { + log_debug!(self.logger, "Peer {} does not support static remote key, disconnecting with no_connection_possible", log_pubkey!(their_node_id)); + return Err(PeerHandleError { no_connection_possible: true }.into()); + } + + Ok(PostInitState::new(sync_status, init_message.features.clone())) + } + + // Add an Init message to the outbound queue + fn queue_init_message(&self, peers_needing_send: &mut HashSet, message_queuer: &mut impl MessageQueuer, pending_outbound_buffer: &mut impl PayloadQueuer, descriptor: &Descriptor, should_request_full_sync: bool) { + let mut features = InitFeatures::known(); + if !should_request_full_sync { + features.clear_initial_routing_sync(); + } + + let resp = msgs::Init { features }; + self.enqueue_message(peers_needing_send, message_queuer, pending_outbound_buffer, descriptor, &resp); + } + + // Process an incoming Init message and set Peer and PeerManager state accordingly + fn process_init_message(&self, message: Message, descriptor: &Descriptor, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap, pending_outbound_buffer: &mut impl PayloadQueuer, outbound: bool, transport: &mut impl ITransport, post_init_state: &mut Option) -> Result<(), PeerHandleError> { + let their_node_id = transport.get_their_node_id(); + + match message { + Message::Init(ref init_message) => { + log_trace!(self.logger, "Received Init message from {}", log_pubkey!(&their_node_id)); + if node_id_to_descriptor.contains_key(&their_node_id) { + log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(&their_node_id)); + return Err(PeerHandleError { no_connection_possible: false }); + } + + let new_post_init_state = self.post_init_state_from_init_message(init_message, &their_node_id)?; + + if let InitSyncTracker::ChannelsSyncing(_) = new_post_init_state.sync_status { + peers_needing_send.insert(descriptor.clone()); + } + + if !outbound { + self.queue_init_message(peers_needing_send, transport, pending_outbound_buffer, descriptor, self.message_handler.route_handler.should_request_full_sync(&their_node_id)); + } + node_id_to_descriptor.insert(their_node_id.clone(), descriptor.clone()); + self.message_handler.chan_handler.peer_connected(&their_node_id, init_message); + *post_init_state = Some(new_post_init_state); + } + _ => { + log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(&their_node_id)); + return Err(PeerHandleError { no_connection_possible: false }) + }, + } + + Ok(()) + } + fn do_read_event(&self, peer_descriptor: &mut Descriptor, data: &[u8], @@ -656,48 +735,29 @@ impl { - - // If the transport is newly connected, do the appropriate set up for the connection - if transport.is_connected() { - let their_node_id = transport.get_their_node_id(); - - match node_id_to_descriptor.entry(their_node_id.clone()) { - hash_map::Entry::Occupied(entry) => { - if entry.get() != peer_descriptor { - // Existing entry in map is from a different descriptor, this is a duplicate - log_trace!(self.logger, "Got second connection with {}, closing", log_pubkey!(&their_node_id)); - return Err(PeerHandleError { no_connection_possible: false }); - } else { - // read_event for existing peer - } - }, - hash_map::Entry::Vacant(entry) => { - log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&their_node_id)); + Ok(newly_connected) => { + if newly_connected { + log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&transport.get_their_node_id())); + } - if outbound { - let mut features = InitFeatures::known(); - if !self.message_handler.route_handler.should_request_full_sync(&their_node_id) { - features.clear_initial_routing_sync(); - } + if newly_connected && outbound { + self.queue_init_message(peers_needing_send, transport, pending_outbound_buffer, peer_descriptor, self.message_handler.route_handler.should_request_full_sync(&transport.get_their_node_id())); + } - let resp = msgs::Init { features }; - self.enqueue_message(peers_needing_send, transport, pending_outbound_buffer, peer_descriptor, &resp); - } - entry.insert(peer_descriptor.clone()); - } - } - } else { - // If the transport layer placed items in the outbound queue, we need - // to schedule ourselves for flush during the next process_events() - if !pending_outbound_buffer.is_empty() { - peers_needing_send.insert(peer_descriptor.clone()); - } + // If the transport layer placed items in the outbound queue, we need + // to schedule ourselves for flush during the next process_events() + if !pending_outbound_buffer.is_empty() { + peers_needing_send.insert(peer_descriptor.clone()); } } } - let received_messages = transport.drain_messages(&*self.logger)?; + let mut received_messages = transport.drain_messages(&*self.logger)?; + + if transport.is_connected() && post_init_state.is_none() && received_messages.len() > 0 { + let init_message = received_messages.remove(0); + self.process_init_message(init_message, peer_descriptor, peers_needing_send, node_id_to_descriptor, pending_outbound_buffer, outbound, transport, post_init_state)?; + } for message in received_messages { macro_rules! try_potential_handleerror { @@ -726,7 +786,7 @@ impl { return Err(e) }, MessageHandlingError::LightningError(e) => { @@ -747,7 +807,6 @@ impl, peer_descriptor: &mut Descriptor, message: wire::Message, - outbound: bool, post_init_state: &mut Option, their_node_id: PublicKey, message_queuer: &mut impl MessageQueuer, @@ -755,63 +814,11 @@ impl Result<(), MessageHandlingError> { log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(&their_node_id)); - // Need an Init as first message - if let wire::Message::Init(_) = message { - } else if post_init_state.is_none() { - log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(&their_node_id)); - return Err(PeerHandleError{ no_connection_possible: false }.into()); - } - match message { // Setup and Control messages: - wire::Message::Init(msg) => { - if msg.features.requires_unknown_bits() { - log_info!(self.logger, "Peer global features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }.into()); - } - if msg.features.requires_unknown_bits() { - log_info!(self.logger, "Peer local features required unknown version bits"); - return Err(PeerHandleError{ no_connection_possible: true }.into()); - } - if post_init_state.is_some() { - return Err(PeerHandleError{ no_connection_possible: false }.into()); - } - - log_info!( - self.logger, "Received peer Init message: data_loss_protect: {}, initial_routing_sync: {}, upfront_shutdown_script: {}, static_remote_key: {}, unknown flags (local and global): {}", - if msg.features.supports_data_loss_protect() { "supported" } else { "not supported"}, - if msg.features.initial_routing_sync() { "requested" } else { "not requested" }, - if msg.features.supports_upfront_shutdown_script() { "supported" } else { "not supported"}, - if msg.features.supports_static_remote_key() { "supported" } else { "not supported"}, - if msg.features.supports_unknown_bits() { "present" } else { "none" } - ); - - let sync_status = if msg.features.initial_routing_sync() { - peers_needing_send.insert(peer_descriptor.clone()); - InitSyncTracker::ChannelsSyncing(0) - } else { - InitSyncTracker::NoSyncRequested - }; - - if !msg.features.supports_static_remote_key() { - log_debug!(self.logger, "Peer {} does not support static remote key, disconnecting with no_connection_possible", log_pubkey!(&their_node_id)); - return Err(PeerHandleError{ no_connection_possible: true }.into()); - } - - if !outbound { - let mut features = InitFeatures::known(); - if !self.message_handler.route_handler.should_request_full_sync(&their_node_id) { - features.clear_initial_routing_sync(); - } - - let resp = msgs::Init { features }; - self.enqueue_message(peers_needing_send, message_queuer, pending_outbound_buffer, &peer_descriptor, &resp); - } - - self.message_handler.chan_handler.peer_connected(&their_node_id, &msg); - - // Initialize the post_init_state now that the Init has been received - *post_init_state = Some(PostInitState::new(sync_status, msg.features)); + wire::Message::Init(_) => { + // 1st Init message handled before handle_message() so this must be a non-first + return Err(PeerHandleError{ no_connection_possible: false }.into()); }, wire::Message::Error(msg) => { let mut data_is_printable = true; @@ -1220,17 +1227,16 @@ impl panic!("Descriptor for disconnect_event is not already known to PeerManager"), Some(peer) => { - if peer.transport.is_connected() { - let node_id = peer.transport.get_their_node_id(); - - if peers.node_id_to_descriptor.get(&node_id).unwrap() == descriptor { - peers.node_id_to_descriptor.remove(&node_id); - self.message_handler.chan_handler.peer_disconnected(&node_id, no_connection_possible); - } else { - // This must have been generated from a duplicate connection error + if peer.is_initialized() { + let their_node_id = peer.transport.get_their_node_id(); + + match peers.node_id_to_descriptor.remove(&their_node_id) { + None => { panic!("Initialized peer must be in node_id_to_descriptor")} + Some(_) => { + peers.node_id_to_descriptor.remove(&their_node_id); + self.message_handler.chan_handler.peer_disconnected(&their_node_id, no_connection_possible); + } } - } else { - // Unconnected nodes never make it into node_id_to_descriptor } } }; @@ -1549,8 +1555,6 @@ mod unit_tests { // Test that an outbound connection with a connected Transport, but no Init message // * read_event() does not call peer_disconnected callback if an error is returned from Transport - // XXXBUG: peer_connected is called after the Init message, but peer_disconnected is called - // with any error after the NOISE handshake is complete #[test] fn outbound_connected_transport_error_does_not_call_peer_disconnected_on_error() { let test_ctx = TestCtx::::new(); @@ -1564,7 +1568,7 @@ mod unit_tests { transport.borrow_mut().process_returns_error(); assert_read_event_errors!(peer_manager, &mut descriptor, false); assert!(!channel_handler_called!(&test_ctx, peer_connected)); - // assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); } // Test that an inbound connection with a connected Transport and queued Init message: @@ -1655,7 +1659,7 @@ mod unit_tests { // Test that an outbound connection with a connected Transport: // * read_event() errors when receiving a Non-Init message first - // * read_event() calls the peer_disconnected channel manager callback + // * read_event() does not call the peer_connected/peer_disconnected callbacks #[test] fn inbound_connected_transport_non_init_first_fails() { let test_ctx = TestCtx::::new(); @@ -1666,12 +1670,13 @@ mod unit_tests { new_inbound!(peer_manager, descriptor, &mut transport); assert_read_event_errors!(peer_manager, &mut descriptor, false); - assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!channel_handler_called!(&test_ctx, peer_connected)); + assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); } // Test that an outbound connection with a connected Transport: // * read_event() errors when receiving a Non-Init message first - // * read_event() calls the peer_disconnected channel manager callback + // * read_event() does not call the peer_connected/peer_disconnected callbacks #[test] fn outbound_connected_transport_non_init_first_fails() { let test_ctx = TestCtx::::new(); @@ -1682,12 +1687,13 @@ mod unit_tests { new_outbound!(peer_manager, descriptor, &mut transport); assert_read_event_errors!(peer_manager, &mut descriptor, false); - assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!channel_handler_called!(&test_ctx, peer_connected)); + assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); } // Test that an inbound connection with a connected Transport: // * read_event() errors out with no_connection_possible if an Init message contains requires_unknown_bits - // * read_event() calls the peer_disconnected channel manager callback + // * read_event() does not call the peer_connected/peer_disconnected callbacks #[test] fn inbound_connected_transport_init_with_required_unknown_first_fails() { let test_ctx = TestCtx::::new(); @@ -1700,12 +1706,13 @@ mod unit_tests { new_inbound!(peer_manager, descriptor, &mut transport); assert_read_event_errors!(peer_manager, &mut descriptor, true); - assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!channel_handler_called!(&test_ctx, peer_connected)); + assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); } // Test that an outbound connection with a connected Transport: // * read_event() errors out with no_connection_possible if an Init message contains requires_unknown_bits - // * read_event() calls the peer_disconnected channel manager callback + // * read_event() does not call the peer_connected/peer_disconnected callbacks #[test] fn outbound_connected_transport_init_with_required_unknown_first_fails() { let test_ctx = TestCtx::::new(); @@ -1718,12 +1725,13 @@ mod unit_tests { new_outbound!(peer_manager, descriptor, &mut transport); assert_read_event_errors!(peer_manager, &mut descriptor, true); - assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!channel_handler_called!(&test_ctx, peer_connected)); + assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); } // Test that an inbound connection with a connected Transport: // * read_event() errors out with no_connection_possible if an Init message does not contain requires_static_remote_key - // * read_event() calls the peer_disconnected channel manager callback + // * read_event() does not call the peer_connected/peer_disconnected callbacks #[test] fn inbound_connected_transport_init_with_clear_requires_static_remote_key() { let test_ctx = TestCtx::::new(); @@ -1736,12 +1744,13 @@ mod unit_tests { new_inbound!(peer_manager, descriptor, &mut transport); assert_read_event_errors!(peer_manager, &mut descriptor, true); - assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!channel_handler_called!(&test_ctx, peer_connected)); + assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); } // Test that an outbound connection with a connected Transport: // * read_event() errors out with no_connection_possible if an Init message does not contain requires_static_remote_key - // * read_event() calls the peer_disconnected channel manager callback + // * read_event() does not call the peer_connected/peer_disconnected callbacks #[test] fn outbound_connected_transport_init_with_clear_requires_static_remote_key() { let test_ctx = TestCtx::::new(); @@ -1754,7 +1763,8 @@ mod unit_tests { new_outbound!(peer_manager, descriptor, &mut transport); assert_read_event_errors!(peer_manager, &mut descriptor, true); - assert!(channel_handler_called!(&test_ctx, peer_disconnected)); + assert!(!channel_handler_called!(&test_ctx, peer_connected)); + assert!(!channel_handler_called!(&test_ctx, peer_disconnected)); } // Test that an inbound connection with a connected Transport and queued Init Message: @@ -1823,11 +1833,14 @@ mod unit_tests { let test_ctx = TestCtx::::new(); let mut descriptor = SocketDescriptorMock::new(); let transport = new_connected_transport!(&test_ctx); - // Create a duplicate connection from the same node_id + + // Create a duplicate connection from the same node_id w/ pending Init message let mut duplicate_connection_descriptor = SocketDescriptorMock::new(); let mut duplicate_connection_transport = RefCell::new(TransportStubBuilder::new() .set_connected(&test_ctx.their_node_id) .finish()); + duplicate_connection_transport.borrow_mut().add_incoming_message(Message::Init(Init { features: InitFeatures::known() })); + let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); assert!(peer_manager.get_peer_node_ids().contains(&test_ctx.their_node_id)); diff --git a/lightning/src/ln/peers/test_util.rs b/lightning/src/ln/peers/test_util.rs index 34330d5c0b1..afe4b9d8995 100644 --- a/lightning/src/ln/peers/test_util.rs +++ b/lightning/src/ln/peers/test_util.rs @@ -242,6 +242,7 @@ impl TransportStubBuilder { is_connected: false, messages: vec![], process_returns_error: false, + returned_newly_connected: false, their_node_id: None, } } @@ -267,6 +268,7 @@ pub(super) struct TransportStub { is_connected: bool, messages: Vec, process_returns_error: bool, + returned_newly_connected: bool, their_node_id: Option, } @@ -285,7 +287,7 @@ impl<'a> ITransport for &'a RefCell { unimplemented!() } - fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result<(), String> { + fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result { self.borrow_mut().process_input(input, output_buffer) } @@ -334,11 +336,19 @@ impl ITransport for TransportStub { unimplemented!() } - fn process_input(&mut self, _input: &[u8], _output_buffer: &mut impl PayloadQueuer) -> Result<(), String> { + fn process_input(&mut self, _input: &[u8], _output_buffer: &mut impl PayloadQueuer) -> Result { if self.process_returns_error { Err("Oh no!".to_string()) } else { - Ok(()) + if self.is_connected() { + + // Simulate the newly_connected behavior by returning Ok(true) on the first call + if !self.returned_newly_connected { + self.returned_newly_connected = true; + return Ok(true) + } + } + return Ok(false) } } diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index 0805148f203..b5402a07431 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -67,7 +67,7 @@ impl ITransport for Transport Result<(), String> { + fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result { match self.conduit { // Continue handshake None => { @@ -82,14 +82,16 @@ impl ITransport for Transport { conduit.read(input); + Ok(false) // newly connected } - }; - - Ok(()) + } } fn drain_messages(&mut self, logger: L) -> Result, PeerHandleError> @@ -246,7 +248,7 @@ mod tests { let mut transport = create_inbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(false)); assert!(!transport.is_connected()); assert_matches!(&spy[..], [_]); @@ -258,7 +260,7 @@ mod tests { let mut transport = create_outbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(false)); assert!(!transport.is_connected()); assert_matches!(&spy[..], [_]); @@ -269,7 +271,7 @@ mod tests { let mut transport = create_inbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(true)); assert!(transport.is_connected()); } @@ -296,7 +298,7 @@ mod tests { let mut transport = create_inbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(true)); let _no_panic = transport.get_their_node_id(); } @@ -305,7 +307,7 @@ mod tests { let mut transport = create_inbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(true)); let _no_panic = transport.get_their_node_id(); } @@ -315,7 +317,7 @@ mod tests { let mut transport = create_outbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(true)); assert!(transport.is_connected()); let _no_panic = transport.get_their_node_id(); } @@ -356,7 +358,7 @@ mod tests { let mut transport = create_inbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(true)); let ping = msgs::Ping { ponglen: 0, @@ -373,7 +375,7 @@ mod tests { let mut transport = create_outbound_for_test::(); let mut spy = Vec::new(); - transport.process_input(&[], &mut spy).unwrap(); + assert_eq!(transport.process_input(&[], &mut spy), Ok(true)); let ping = msgs::Ping { ponglen: 0, From 2a790cc08b2e5663940534422f8d6aa3a4ab1f7b Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 7 Sep 2020 19:17:51 -0700 Subject: [PATCH 84/96] refactor: Clean up the previously destructured read_event() path Now that the Init handling has been moved and the dependencies are more clear, deduplicate the parameters of the read_event() and helper functions to make use of Peer. The overall pattern remains the same, read_event() does the locking and passes in the separate items (peer, peers_needing_send, node_id_to_descriptor) to do_read_event(). The handle_message() path is also cleaned up now that post_init_state is guaranteed to be valid at that point. --- lightning/src/ln/peers/handler.rs | 87 ++++++++++++------------------- 1 file changed, 33 insertions(+), 54 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 920cf724f82..472a0bb71fa 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -623,7 +623,7 @@ impl panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => peer }; - self.do_read_event(peer_descriptor, data, peer.outbound, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer, &mut peers.node_id_to_descriptor, &mut peers.peers_needing_send) + self.do_read_event(peer_descriptor, peer, &mut peers.peers_needing_send, &mut peers.node_id_to_descriptor, data) }; match result { @@ -676,19 +676,19 @@ impl, message_queuer: &mut impl MessageQueuer, pending_outbound_buffer: &mut impl PayloadQueuer, descriptor: &Descriptor, should_request_full_sync: bool) { + fn queue_init_message(&self, descriptor: &Descriptor, peer: &mut Peer, peers_needing_send: &mut HashSet) { let mut features = InitFeatures::known(); - if !should_request_full_sync { + if !self.message_handler.route_handler.should_request_full_sync(&peer.transport.get_their_node_id()) { features.clear_initial_routing_sync(); } let resp = msgs::Init { features }; - self.enqueue_message(peers_needing_send, message_queuer, pending_outbound_buffer, descriptor, &resp); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, descriptor, &resp); } // Process an incoming Init message and set Peer and PeerManager state accordingly - fn process_init_message(&self, message: Message, descriptor: &Descriptor, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap, pending_outbound_buffer: &mut impl PayloadQueuer, outbound: bool, transport: &mut impl ITransport, post_init_state: &mut Option) -> Result<(), PeerHandleError> { - let their_node_id = transport.get_their_node_id(); + fn process_init_message(&self, message: Message, descriptor: &Descriptor, peer: &mut Peer, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap) -> Result<(), PeerHandleError> { + let their_node_id = peer.transport.get_their_node_id(); match message { Message::Init(ref init_message) => { @@ -704,12 +704,14 @@ impl { log_trace!(self.logger, "Peer {} sent non-Init first message", log_pubkey!(&their_node_id)); @@ -720,43 +722,35 @@ impl, - transport: &mut impl ITransport, - pending_outbound_buffer: &mut impl PayloadQueuer, - node_id_to_descriptor: &mut HashMap, - peers_needing_send: &mut HashSet) -> Result { + fn do_read_event(&self, peer_descriptor: &mut Descriptor, peer: &mut Peer, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap, data: &[u8]) -> Result { let pause_read = { - match transport.process_input(data, pending_outbound_buffer) { + match peer.transport.process_input(data, &mut peer.pending_outbound_buffer) { Err(e) => { log_trace!(self.logger, "Error while processing input: {}", e); return Err(PeerHandleError { no_connection_possible: false }) }, Ok(newly_connected) => { if newly_connected { - log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&transport.get_their_node_id())); + log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&peer.transport.get_their_node_id())); } - if newly_connected && outbound { - self.queue_init_message(peers_needing_send, transport, pending_outbound_buffer, peer_descriptor, self.message_handler.route_handler.should_request_full_sync(&transport.get_their_node_id())); + if newly_connected && peer.outbound { + self.queue_init_message(peer_descriptor, peer, peers_needing_send); } // If the transport layer placed items in the outbound queue, we need // to schedule ourselves for flush during the next process_events() - if !pending_outbound_buffer.is_empty() { + if !peer.pending_outbound_buffer.is_empty() { peers_needing_send.insert(peer_descriptor.clone()); } } } - let mut received_messages = transport.drain_messages(&*self.logger)?; + let mut received_messages = peer.transport.drain_messages(&*self.logger)?; - if transport.is_connected() && post_init_state.is_none() && received_messages.len() > 0 { + if peer.transport.is_connected() && peer.post_init_state.is_none() && received_messages.len() > 0 { let init_message = received_messages.remove(0); - self.process_init_message(init_message, peer_descriptor, peers_needing_send, node_id_to_descriptor, pending_outbound_buffer, outbound, transport, post_init_state)?; + self.process_init_message(init_message, peer_descriptor, peer, peers_needing_send, node_id_to_descriptor)?; } for message in received_messages { @@ -777,7 +771,7 @@ impl { log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - self.enqueue_message(peers_needing_send, transport, pending_outbound_buffer, peer_descriptor, &msg); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, peer_descriptor, &msg); continue; }, } @@ -786,7 +780,7 @@ impl { return Err(e) }, MessageHandlingError::LightningError(e) => { @@ -796,7 +790,7 @@ impl, - peer_descriptor: &mut Descriptor, message: wire::Message, - post_init_state: &mut Option, - their_node_id: PublicKey, - message_queuer: &mut impl MessageQueuer, - pending_outbound_buffer: &mut impl PayloadQueuer - ) -> Result<(), MessageHandlingError> { + peer_descriptor: &mut Descriptor, + peer: &mut Peer, + peers_needing_send: &mut HashSet) -> Result<(), MessageHandlingError> { + + let their_node_id = peer.transport.get_their_node_id(); + let post_init_state = peer.post_init_state.as_mut().unwrap(); log_trace!(self.logger, "Received message of type {} from {}", message.type_id(), log_pubkey!(&their_node_id)); match message { @@ -843,33 +836,19 @@ impl { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; - self.enqueue_message(peers_needing_send, message_queuer, pending_outbound_buffer, &peer_descriptor, &resp); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, &peer_descriptor, &resp); } }, wire::Message::Pong(_msg) => { - if let Some(ref mut state) = post_init_state { - state.awaiting_pong = false; - } else { - panic!("Received Pong before Init and didn't catch it earlier!"); - } + post_init_state.awaiting_pong = false; }, // Channel messages: wire::Message::OpenChannel(msg) => { - match post_init_state { - None => panic!("Received OpenChannel before Init and didn't catch it earlier!"), - Some(state) => { - self.message_handler.chan_handler.handle_open_channel(&their_node_id, state.their_features.clone(), &msg); - } - } + self.message_handler.chan_handler.handle_open_channel(&their_node_id, post_init_state.their_features.clone(), &msg); }, wire::Message::AcceptChannel(msg) => { - match post_init_state { - None => panic!("Received AcceptChannel before Init and didn't catch it earlier!"), - Some(state) => { - self.message_handler.chan_handler.handle_accept_channel(&their_node_id, state.their_features.clone(), &msg); - } - } + self.message_handler.chan_handler.handle_accept_channel(&their_node_id, post_init_state.their_features.clone(), &msg); }, wire::Message::FundingCreated(msg) => { From 6e7f4e194cd8d58cffaf26d1f1993dfb56c3126b Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Mon, 7 Sep 2020 19:21:58 -0700 Subject: [PATCH 85/96] refactor: Remove scoping from do_read_event() Now that the locking and destructuring is done in read_event(), the workarounds for the pre-NLL borrow checker can go away. --- lightning/src/ln/peers/handler.rs | 113 +++++++++++++++--------------- 1 file changed, 55 insertions(+), 58 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 472a0bb71fa..4fea0a9fb5d 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -723,77 +723,74 @@ impl, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap, data: &[u8]) -> Result { - let pause_read = { - match peer.transport.process_input(data, &mut peer.pending_outbound_buffer) { - Err(e) => { - log_trace!(self.logger, "Error while processing input: {}", e); - return Err(PeerHandleError { no_connection_possible: false }) - }, - Ok(newly_connected) => { - if newly_connected { - log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&peer.transport.get_their_node_id())); - } - if newly_connected && peer.outbound { - self.queue_init_message(peer_descriptor, peer, peers_needing_send); - } + match peer.transport.process_input(data, &mut peer.pending_outbound_buffer) { + Err(e) => { + log_trace!(self.logger, "Error while processing input: {}", e); + return Err(PeerHandleError { no_connection_possible: false }) + }, + Ok(newly_connected) => { + if newly_connected { + log_trace!(self.logger, "Finished noise handshake for connection with {}", log_pubkey!(&peer.transport.get_their_node_id())); + } - // If the transport layer placed items in the outbound queue, we need - // to schedule ourselves for flush during the next process_events() - if !peer.pending_outbound_buffer.is_empty() { - peers_needing_send.insert(peer_descriptor.clone()); - } + if newly_connected && peer.outbound { + self.queue_init_message(peer_descriptor, peer, peers_needing_send); + } + + // If the transport layer placed items in the outbound queue, we need + // to schedule ourselves for flush during the next process_events() + if !peer.pending_outbound_buffer.is_empty() { + peers_needing_send.insert(peer_descriptor.clone()); } } + } - let mut received_messages = peer.transport.drain_messages(&*self.logger)?; + let mut received_messages = peer.transport.drain_messages(&*self.logger)?; - if peer.transport.is_connected() && peer.post_init_state.is_none() && received_messages.len() > 0 { - let init_message = received_messages.remove(0); - self.process_init_message(init_message, peer_descriptor, peer, peers_needing_send, node_id_to_descriptor)?; - } + if peer.transport.is_connected() && peer.post_init_state.is_none() && received_messages.len() > 0 { + let init_message = received_messages.remove(0); + self.process_init_message(init_message, peer_descriptor, peer, peers_needing_send, node_id_to_descriptor)?; + } - for message in received_messages { - macro_rules! try_potential_handleerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(e) => { - match e.action { - msgs::ErrorAction::DisconnectPeer { msg: _ } => { - //TODO: Try to push msg - log_trace!(self.logger, "Got Err handling message, disconnecting peer because {}", e.err); - return Err(PeerHandleError{ no_connection_possible: false }); - }, - msgs::ErrorAction::IgnoreError => { - log_trace!(self.logger, "Got Err handling message, ignoring because {}", e.err); - continue; - }, - msgs::ErrorAction::SendErrorMessage { msg } => { - log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, peer_descriptor, &msg); - continue; - }, - } + for message in received_messages { + macro_rules! try_potential_handleerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(e) => { + match e.action { + msgs::ErrorAction::DisconnectPeer { msg: _ } => { + //TODO: Try to push msg + log_trace!(self.logger, "Got Err handling message, disconnecting peer because {}", e.err); + return Err(PeerHandleError{ no_connection_possible: false }); + }, + msgs::ErrorAction::IgnoreError => { + log_trace!(self.logger, "Got Err handling message, ignoring because {}", e.err); + continue; + }, + msgs::ErrorAction::SendErrorMessage { msg } => { + log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, peer_descriptor, &msg); + continue; + }, } - }; - } + } + }; } + } - if let Err(handling_error) = self.handle_message(message, peer_descriptor, peer, peers_needing_send) { - match handling_error { - MessageHandlingError::PeerHandleError(e) => { return Err(e) }, - MessageHandlingError::LightningError(e) => { - try_potential_handleerror!(Err(e)); - }, - } + if let Err(handling_error) = self.handle_message(message, peer_descriptor, peer, peers_needing_send) { + match handling_error { + MessageHandlingError::PeerHandleError(e) => { return Err(e) }, + MessageHandlingError::LightningError(e) => { + try_potential_handleerror!(Err(e)); + }, } } + } - peer.pending_outbound_buffer.queue_space() == 0 // pause_read - }; - - Ok(pause_read) + Ok(peer.pending_outbound_buffer.queue_space() == 0) // pause_read } /// Process an incoming message and return a decision (ok, lightning error, peer handling error) regarding the next action with the peer From 249c414fa755ffe3e4c73810ff8561aa34ea2217 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 8 Sep 2020 10:44:50 -0700 Subject: [PATCH 86/96] refactor: Clean up the PeerHolder access/iteration/remove This patch expands the PeerHolder API allowing for encapsulation of the peer state from the code that needs to iterate over initialized peers. This cleans up peer iteration/removal allowing for a much simpler design. 1) Introduce new APIs for PeerHolder: * initialized_peers_mut() * initialized_peer_node_ids() * remove_peer_by_descriptor() 2) Clean up event handler iteration using new APIs 3) Unify the timer_tick and DisconnectPeer event disconnect path using new APIs 4) Convert get_peer_node_ids() to use new API --- lightning/src/ln/peers/handler.rs | 203 ++++++++++++++---------------- 1 file changed, 97 insertions(+), 106 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 4fea0a9fb5d..df687bd9b23 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -31,6 +31,8 @@ use bitcoin::hashes::sha256::HashEngine as Sha256Engine; use bitcoin::hashes::{HashEngine, Hash}; use ln::peers::outbound_queue::OutboundQueue; use ln::peers::transport::{PayloadQueuer, Transport}; +use bitcoin::hashes::core::iter::Filter; +use std::collections::hash_map::IterMut; const MSG_BUFF_SIZE: usize = 10; @@ -243,7 +245,7 @@ struct PeerHolder { } impl PeerHolder { - fn initialized_peer_by_node_id(&mut self, node_id: &PublicKey) -> Option<(Descriptor, &mut Peer)> { + fn initialized_peer_by_node_id_mut(&mut self, node_id: &PublicKey) -> Option<(Descriptor, &mut Peer)> { match self.node_id_to_descriptor.get_mut(node_id) { None => None, Some(descriptor) => { @@ -254,7 +256,7 @@ impl PeerHolder { // their_features is set after receiving an Init message - if !peer.is_initialized() { + if peer.post_init_state.is_none() { None } else { Some((descriptor.clone(), peer)) @@ -264,6 +266,40 @@ impl PeerHolder(&'a mut self) -> Filter>, fn(&(&'a Descriptor, &'a mut Peer)) -> bool> { + self.peers.iter_mut().filter(| entry | { + entry.1.post_init_state.is_some() + }) + } + + // Returns the node id's of the subset of peers that are initialized + fn initialized_peer_node_ids(&self) -> Vec { + self.node_id_to_descriptor.keys().cloned().collect() + } + + // Removes all associated metadata for descriptor and returns the Peer object associated with it + fn remove_peer_by_descriptor(&mut self, descriptor: &Descriptor) -> Peer { + // may or may not be in this set depending on in-flight messages + self.peers_needing_send.remove(descriptor); + + let peer_option = self.peers.remove(descriptor); + match peer_option { + None => panic!("Descriptor for disconnect_event is not already known to PeerManager"), + Some(peer) => { + if peer.post_init_state.is_some() { + let their_node_id = peer.transport.get_their_node_id(); + + match self.node_id_to_descriptor.remove(&their_node_id) { + None => { panic!("Initialized peer must be in node_id_to_descriptor")} + Some(removed_descriptor) => { assert!(&removed_descriptor == descriptor, "Invalid PeerHolder state. Descriptors do not match!") } + } + } + peer + } + } + } } #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] @@ -476,12 +512,7 @@ impl Vec { let peers = self.peers.lock().unwrap(); - peers.peers.values().filter_map(|p| { - if !p.is_initialized() { - return None; - } - Some(p.transport.get_their_node_id()) - }).collect() + peers.initialized_peer_node_ids() } fn get_ephemeral_key(&self) -> SecretKey { @@ -617,8 +648,8 @@ impl Result { - let result = { - let peers = &mut *self.peers.lock().unwrap(); + let peers = &mut *self.peers.lock().unwrap(); + let result = { let peer = match peers.peers.get_mut(peer_descriptor) { None => panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => peer @@ -629,7 +660,7 @@ impl Ok(res), Err(e) => { - self.disconnect_event_internal(peer_descriptor, e.no_connection_possible); + self.disconnect_event_internal(peer_descriptor, e.no_connection_possible, peers); Err(e) } } @@ -955,7 +986,7 @@ impl { log_trace!(self.logger, "Handling BroadcastChannelAnnouncement event in peer_handler for short channel id {}", msg.contents.short_channel_id); if self.message_handler.route_handler.handle_channel_announcement(msg).is_ok() && self.message_handler.route_handler.handle_channel_update(update_msg).is_ok() { - for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.is_initialized() || - !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { + for (descriptor, peer) in peers.initialized_peers_mut() { + if !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { continue } @@ -1116,9 +1146,8 @@ impl { log_trace!(self.logger, "Handling BroadcastNodeAnnouncement event in peer_handler"); if self.message_handler.route_handler.handle_node_announcement(msg).is_ok() { - for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.is_initialized() || - !peer.should_forward_node_announcement(msg.contents.node_id) { + for (descriptor, peer) in peers.initialized_peers_mut() { + if !peer.should_forward_node_announcement(msg.contents.node_id) { continue } peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); @@ -1129,9 +1158,8 @@ impl { log_trace!(self.logger, "Handling BroadcastChannelUpdate event in peer_handler for short channel id {}", msg.contents.short_channel_id); if self.message_handler.route_handler.handle_channel_update(msg).is_ok() { - for (ref descriptor, ref mut peer) in peers.peers.iter_mut() { - if !peer.is_initialized() || - !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { + for (descriptor, peer) in peers.initialized_peers_mut() { + if !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { continue } peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); @@ -1145,25 +1173,28 @@ impl { match *action { msgs::ErrorAction::DisconnectPeer { ref msg } => { - if let Some(mut descriptor) = peers.node_id_to_descriptor.remove(node_id) { - peers.peers_needing_send.remove(&descriptor); - if let Some(mut peer) = peers.peers.remove(&descriptor) { + let descriptor_to_disconnect_option = match peers.initialized_peer_by_node_id_mut(node_id) { + None => { None /* ignore unknown or uninitialized peers */ } + Some((mut descriptor, peer)) => { if let Some(ref msg) = *msg { log_trace!(self.logger, "Handling DisconnectPeer HandleError event in peer_handler for node {} with message {}", log_pubkey!(node_id), msg.data); - if peer.transport.is_connected() { - peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); - } + peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + // This isn't guaranteed to work, but if there is enough free // room in the send buffer, put the error message there... self.do_attempt_write_data(&mut descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); } else { log_trace!(self.logger, "Handling DisconnectPeer HandleError event in peer_handler for node {} with no message", log_pubkey!(node_id)); } + Some(descriptor) } + }; + + if let Some(mut descriptor) = descriptor_to_disconnect_option { + self.disconnect_event_internal(&descriptor, false, peers); descriptor.disconnect_socket(); - self.message_handler.chan_handler.peer_disconnected(&node_id, false); } }, msgs::ErrorAction::IgnoreError => {}, @@ -1171,7 +1202,7 @@ impl panic!("Descriptor for disconnect_event is not already known to PeerManager"), - Some(peer) => { - if peer.is_initialized() { - let their_node_id = peer.transport.get_their_node_id(); + fn disconnect_event_internal(&self, descriptor: &Descriptor, no_connection_possible: bool, peers: &mut PeerHolder) { + let peer = peers.remove_peer_by_descriptor(descriptor); - match peers.node_id_to_descriptor.remove(&their_node_id) { - None => { panic!("Initialized peer must be in node_id_to_descriptor")} - Some(_) => { - peers.node_id_to_descriptor.remove(&their_node_id); - self.message_handler.chan_handler.peer_disconnected(&their_node_id, no_connection_possible); - } - } - } - } - }; + if peer.is_initialized() { + self.message_handler.chan_handler.peer_disconnected(&peer.transport.get_their_node_id(), no_connection_possible); + } } fn timer_tick_occured(&self) { - let mut peers_lock = self.peers.lock().unwrap(); - { - let peers = &mut *peers_lock; - let peers_needing_send = &mut peers.peers_needing_send; - let node_id_to_descriptor = &mut peers.node_id_to_descriptor; - let peers = &mut peers.peers; - let mut descriptors_needing_disconnect = Vec::new(); - - peers.retain(|descriptor, peer| { - let needs_to_write_data = match peer.post_init_state { - None => return true, // retain - Some(ref mut post_init_state) => { - if post_init_state.awaiting_pong { - peers_needing_send.remove(descriptor); - descriptors_needing_disconnect.push(descriptor.clone()); - let their_node_id = peer.transport.get_their_node_id(); - log_trace!(self.logger, "Disconnecting peer with id {} due to ping timeout", their_node_id); - node_id_to_descriptor.remove(&their_node_id); - self.message_handler.chan_handler.peer_disconnected(&their_node_id, false); - - return false; // retain - } - - if peer.transport.is_connected() { - let ping = msgs::Ping { - ponglen: 0, - byteslen: 64, - }; - peer.transport.enqueue_message(&ping, &mut peer.pending_outbound_buffer, &*self.logger); - post_init_state.awaiting_pong = true; - - true // needs_to_write_data - } else { - false // !needs_to_write_data - } - } + let peers = &mut *self.peers.lock().unwrap(); + let mut descriptors_needing_disconnect = Vec::new(); + + for (descriptor, peer) in peers.initialized_peers_mut() { + // Mark peers that haven't sent a pong for disconnect + if peer.post_init_state.as_ref().unwrap().awaiting_pong { + log_trace!(self.logger, "Disconnecting peer with id {} due to ping timeout", &peer.transport.get_their_node_id()); + descriptors_needing_disconnect.push(descriptor.clone()); + } else { + let ping = msgs::Ping { + ponglen: 0, + byteslen: 64, }; - - if needs_to_write_data { - let mut descriptor_clone = descriptor.clone(); - self.do_attempt_write_data(&mut descriptor_clone, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); - } - - true // retain - }); - - for mut descriptor in descriptors_needing_disconnect.drain(..) { - descriptor.disconnect_socket(); + peer.transport.enqueue_message(&ping, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut descriptor.clone(), &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); + peer.post_init_state.as_mut().unwrap().awaiting_pong = true; } } + + for mut descriptor in descriptors_needing_disconnect.drain(..) { + self.disconnect_event_internal(&descriptor, false, peers); + descriptor.disconnect_socket(); + } } } From d043d7659bce766eaa415a9b9bcebd6623566b9b Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 8 Sep 2020 11:13:29 -0700 Subject: [PATCH 87/96] fix: Handle Ok(false) from route_handler callbacks in event path The broadcast event handling code did not catch Ok(false) returned from the route handler when deciding whether or not to broadcast messages. Instead, it only checked if the return value was an Error. Fix it up and enable the regression tests. --- lightning/src/ln/peers/handler.rs | 70 +++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index df687bd9b23..21ae327e12a 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -1127,7 +1127,23 @@ impl { log_trace!(self.logger, "Handling BroadcastChannelAnnouncement event in peer_handler for short channel id {}", msg.contents.short_channel_id); - if self.message_handler.route_handler.handle_channel_announcement(msg).is_ok() && self.message_handler.route_handler.handle_channel_update(update_msg).is_ok() { + let route_handler_wants_broadcast = match self.message_handler.route_handler.handle_channel_announcement(msg) { + Err(e) => { + log_trace!(self.logger, "Ignoring because handle_channel_announcement returned error: {:?}", e); + false + } + Ok(false) => false, + Ok(true) => { + match self.message_handler.route_handler.handle_channel_update(update_msg) { + Err(e) => { + log_trace!(self.logger, "Ignoring because handle_channel_update returned error: {:?}", e); + false + }, + Ok(result) => result + } + } + }; + if route_handler_wants_broadcast { for (descriptor, peer) in peers.initialized_peers_mut() { if !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { continue @@ -1145,26 +1161,38 @@ impl { log_trace!(self.logger, "Handling BroadcastNodeAnnouncement event in peer_handler"); - if self.message_handler.route_handler.handle_node_announcement(msg).is_ok() { - for (descriptor, peer) in peers.initialized_peers_mut() { - if !peer.should_forward_node_announcement(msg.contents.node_id) { - continue + match self.message_handler.route_handler.handle_node_announcement(msg) { + Err(e) => { + log_trace!(self.logger, "Ignoring because handle_node_announcement returned error: {:?}", e); + }, + Ok(true) => { + for (descriptor, peer) in peers.initialized_peers_mut() { + if !peer.should_forward_node_announcement(msg.contents.node_id) { + continue + } + peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut (*descriptor).clone(), &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); } - peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); - self.do_attempt_write_data(&mut (*descriptor).clone(), &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); - } + }, + Ok(false) => { } } }, MessageSendEvent::BroadcastChannelUpdate { ref msg } => { log_trace!(self.logger, "Handling BroadcastChannelUpdate event in peer_handler for short channel id {}", msg.contents.short_channel_id); - if self.message_handler.route_handler.handle_channel_update(msg).is_ok() { - for (descriptor, peer) in peers.initialized_peers_mut() { - if !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { - continue + match self.message_handler.route_handler.handle_channel_update(msg) { + Err(e) => { + log_trace!(self.logger, "Ignoring because handle_channel_update returned error: {:?}", e); + }, + Ok(true) => { + for (descriptor, peer) in peers.initialized_peers_mut() { + if !peer.should_forward_channel_announcement(msg.contents.short_channel_id) { + continue + } + peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); + self.do_attempt_write_data(&mut (*descriptor).clone(), &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); } - peer.transport.enqueue_message(msg, &mut peer.pending_outbound_buffer, &*self.logger); - self.do_attempt_write_data(&mut (*descriptor).clone(), &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); - } + }, + Ok(false) => { } } }, MessageSendEvent::PaymentFailureNetworkUpdate { ref update } => { @@ -2459,7 +2487,6 @@ mod unit_tests { // Test that a post-Init connection: // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the // route_handler.handle_channel_announcement returns false - // XXXBUG: Implementation does not check return value of handle_channel_announcement, only that it didn't error #[test] fn post_init_broadcast_channel_announcement_route_handler_handle_announcement_returns_false() { let channel_handler = TestChannelMessageHandler::new(); @@ -2476,13 +2503,12 @@ mod unit_tests { let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); peer_manager.process_events(); - // assert!(descriptor.get_recording().is_empty()); + assert!(descriptor.get_recording().is_empty()); } // Test that a post-Init connection: // * process_events() sends nothing when it receives a BroadcastChannelAnnouncement if the // route_handler.handle_channel_update returns false - // XXXBUG: Implementation does not check return value of handle_channel_update, only that it didn't error #[test] fn post_init_broadcast_channel_announcement_route_handle_update_returns_false() { let channel_handler = TestChannelMessageHandler::new(); @@ -2499,7 +2525,7 @@ mod unit_tests { let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); peer_manager.process_events(); - // assert!(descriptor.get_recording().is_empty()); + assert!(descriptor.get_recording().is_empty()); } // To reduce test expansion, the unconnected and connected transport tests are only run on one @@ -2664,7 +2690,6 @@ mod unit_tests { // Test that a post-Init connection: // * process_events() sends nothing when it receives a BroadcastNodeAnnouncement if the // route_handler.handle_node_announcement returns false - // XXXBUG: Implementation does not check return value of handle_node_announcement, only that it didn't error #[test] fn post_init_broadcast_node_announcement_route_handler_handle_announcement_returns_false() { let channel_handler = TestChannelMessageHandler::new(); @@ -2680,7 +2705,7 @@ mod unit_tests { let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); peer_manager.process_events(); - // assert!(descriptor.get_recording().is_empty()); + assert!(descriptor.get_recording().is_empty()); } // Test that a post-Init connection: @@ -2728,7 +2753,6 @@ mod unit_tests { // Test that a post-Init connection: // * process_events() sends nothing when it receives a BroadcastChannelUpdate if the // route_handler.handle_channel_update returns false - // XXXBUG: Implementation does not check return value of handle_node_announcement, only that it didn't error #[test] fn post_init_broadcast_channel_update_route_handler_handle_update_returns_false() { let channel_handler = TestChannelMessageHandler::new(); @@ -2744,7 +2768,7 @@ mod unit_tests { let peer_manager = new_peer_manager_post_init!(&test_ctx, &mut descriptor, &transport); peer_manager.process_events(); - // assert!(descriptor.get_recording().is_empty()); + assert!(descriptor.get_recording().is_empty()); } // Test that a post-Init connection: From f4238be907120679b516478fdcf82de462fb172a Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 8 Sep 2020 11:30:46 -0700 Subject: [PATCH 88/96] fix: Use a separate lock for the ephemeral_key_midstate Use a separate lock to generate the SecretKey instead of overloading the PeerHolder mutex. Refactoring PeerManager removed this hidden constraint and this should make it more robust in the future. --- lightning/src/ln/peers/handler.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 21ae327e12a..1d9d3425e32 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -350,7 +350,7 @@ struct PeerManagerImpl, peers: Mutex>, our_node_secret: SecretKey, - ephemeral_key_midstate: Sha256Engine, + ephemeral_key_midstate: Mutex, // Usize needs to be at least 32 bits to avoid overflowing both low and high. If usize is 64 // bits we will never realistically count into high: @@ -503,7 +503,7 @@ impl SecretKey { - let mut ephemeral_hash = self.ephemeral_key_midstate.clone(); + let mut ephemeral_hash = self.ephemeral_key_midstate.lock().unwrap().clone(); let low = self.peer_counter_low.fetch_add(1, Ordering::AcqRel); let high = if low == 0 { self.peer_counter_high.fetch_add(1, Ordering::AcqRel) From ab2c8cf38aeac974dc841881d2ac908489ce16a9 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 8 Sep 2020 13:56:20 -0700 Subject: [PATCH 89/96] rename: s/pending_outbound_buffer/outbound_queue/ s/fill_message_queue_with_sync/fill_outbound_queue_with_sync/ s/queue_init_message/enqueue_init_message/ --- lightning/src/ln/peers/handler.rs | 134 +++++++++++++++--------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 1d9d3425e32..389934e50fc 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -180,7 +180,7 @@ impl PostInitState { struct Peer { outbound: bool, - pending_outbound_buffer: OutboundQueue, + outbound_queue: OutboundQueue, post_init_state: Option, transport: TransportImpl, } @@ -189,7 +189,7 @@ impl Peer { fn new(outbound: bool, transport: TransportImpl) -> Self { Self { outbound, - pending_outbound_buffer: OutboundQueue::new(MSG_BUFF_SIZE), + outbound_queue: OutboundQueue::new(MSG_BUFF_SIZE), post_init_state: None, transport } @@ -558,13 +558,13 @@ impl( + fn fill_outbound_queue_with_sync( &self, sync_status: &mut InitSyncTracker, message_queuer: &mut impl MessageQueuer, - pending_outbound_buffer: &mut Q) { + outbound_queue: &mut Q) { - let queue_space = pending_outbound_buffer.queue_space(); + let queue_space = outbound_queue.queue_space(); if queue_space > 0 { match sync_status { &mut InitSyncTracker::NoSyncRequested => {}, @@ -572,12 +572,12 @@ impl, message_queuer: &mut impl MessageQueuer, - pending_outbound_buffer: &mut Q) { + outbound_queue: &mut Q) { - while !pending_outbound_buffer.is_blocked() { + while !outbound_queue.is_blocked() { // If connected, fill output queue with sync messages match post_init_state { None => {}, - &mut Some(ref mut state) => self.fill_message_queue_with_sync(&mut state.sync_status, message_queuer, pending_outbound_buffer) + &mut Some(ref mut state) => self.fill_outbound_queue_with_sync(&mut state.sync_status, message_queuer, outbound_queue) } // No messages to send - if pending_outbound_buffer.is_empty() { + if outbound_queue.is_empty() { break; } - pending_outbound_buffer.try_flush_one(descriptor); + outbound_queue.try_flush_one(descriptor); } } @@ -640,8 +640,8 @@ impl panic!("Descriptor for write_event is not already known to PeerManager"), Some(peer) => { - peer.pending_outbound_buffer.unblock(); - self.do_attempt_write_data(descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer); + peer.outbound_queue.unblock(); + self.do_attempt_write_data(descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.outbound_queue); } }; Ok(()) @@ -707,14 +707,14 @@ impl, peers_needing_send: &mut HashSet) { + fn enqueue_init_message(&self, descriptor: &Descriptor, peer: &mut Peer, peers_needing_send: &mut HashSet) { let mut features = InitFeatures::known(); if !self.message_handler.route_handler.should_request_full_sync(&peer.transport.get_their_node_id()) { features.clear_initial_routing_sync(); } let resp = msgs::Init { features }; - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, descriptor, &resp); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.outbound_queue, descriptor, &resp); } // Process an incoming Init message and set Peer and PeerManager state accordingly @@ -736,7 +736,7 @@ impl, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap, data: &[u8]) -> Result { - match peer.transport.process_input(data, &mut peer.pending_outbound_buffer) { + match peer.transport.process_input(data, &mut peer.outbound_queue) { Err(e) => { log_trace!(self.logger, "Error while processing input: {}", e); return Err(PeerHandleError { no_connection_possible: false }) @@ -766,12 +766,12 @@ impl { log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, peer_descriptor, &msg); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.outbound_queue, peer_descriptor, &msg); continue; }, } @@ -821,7 +821,7 @@ impl { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.pending_outbound_buffer, &peer_descriptor, &resp); + self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.outbound_queue, &peer_descriptor, &resp); } }, wire::Message::Pong(_msg) => { @@ -987,8 +987,8 @@ impl { } @@ -1188,8 +1188,8 @@ impl { } @@ -1208,11 +1208,11 @@ impl self.do_attempt_write_data(&mut descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.pending_outbound_buffer), + Some(peer) => self.do_attempt_write_data(&mut descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.outbound_queue), None => panic!("Inconsistent peers set state!"), } } @@ -1278,8 +1278,8 @@ impl Date: Thu, 10 Sep 2020 08:29:12 -0700 Subject: [PATCH 90/96] Remove peers_needing_send set Motivated by rust-bitcoin/rust-lightning#456, remove the peers_needing_send set in favor of just scanning the peers during process_events() and attempting to send data for those peers that have items in their outbound queue or pending sync items to be sent out. --- lightning/src/ln/peers/handler.rs | 76 ++++++++++++++----------------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/lightning/src/ln/peers/handler.rs b/lightning/src/ln/peers/handler.rs index 389934e50fc..305cc5975cf 100644 --- a/lightning/src/ln/peers/handler.rs +++ b/lightning/src/ln/peers/handler.rs @@ -20,7 +20,7 @@ use util::events::{MessageSendEvent, MessageSendEventsProvider}; use util::logger::Logger; use routing::network_graph::NetGraphMsgHandler; -use std::collections::{HashMap,HashSet}; +use std::collections::HashMap; use std::sync::{Arc, Mutex}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::{cmp,error,hash,fmt}; @@ -237,9 +237,6 @@ impl Peer { struct PeerHolder { peers: HashMap>, - /// Added to by do_read_event for cases where we pushed a message onto the send buffer but - /// didn't call do_attempt_write_data to avoid reentrancy. Cleared in process_events() - peers_needing_send: HashSet, /// Peers in this map have completed the NOISE handshake and received an Init message node_id_to_descriptor: HashMap, } @@ -281,9 +278,6 @@ impl PeerHolder Peer { - // may or may not be in this set depending on in-flight messages - self.peers_needing_send.remove(descriptor); - let peer_option = self.peers.remove(descriptor); match peer_option { None => panic!("Descriptor for disconnect_event is not already known to PeerManager"), @@ -300,6 +294,23 @@ impl PeerHolder(&'a mut self) -> Filter>, fn(&(&'a Descriptor, &'a mut Peer)) -> bool> { + self.peers.iter_mut().filter(|(_, peer)| { + let has_outbound_sync = match &peer.post_init_state { + None => false, + Some(post_init_state) => match &post_init_state.sync_status { + InitSyncTracker::NoSyncRequested => false, + InitSyncTracker::ChannelsSyncing(_) => true, + InitSyncTracker::NodesSyncing(_) => true, + } + }; + + has_outbound_sync || !peer.outbound_queue.is_empty() + }) + } } #[cfg(not(any(target_pointer_width = "32", target_pointer_width = "64")))] @@ -499,7 +510,6 @@ impl panic!("Descriptor for read_event is not already known to PeerManager"), Some(peer) => peer }; - self.do_read_event(peer_descriptor, peer, &mut peers.peers_needing_send, &mut peers.node_id_to_descriptor, data) + self.do_read_event(peer_descriptor, peer, &mut peers.node_id_to_descriptor, data) }; match result { @@ -666,12 +676,6 @@ impl(&self, peers_needing_send: &mut HashSet, message_queuer: &mut impl MessageQueuer, output_buffer: &mut impl PayloadQueuer, descriptor: &Descriptor, message: &M) { - message_queuer.enqueue_message(message, output_buffer, &*self.logger); - peers_needing_send.insert(descriptor.clone()); - } - // Returns a valid PostInitState given a Init message fn post_init_state_from_init_message(&self, init_message: &msgs::Init, their_node_id: &PublicKey) -> Result { if init_message.features.requires_unknown_bits() { @@ -707,18 +711,18 @@ impl, peers_needing_send: &mut HashSet) { + fn enqueue_init_message(&self, peer: &mut Peer) { let mut features = InitFeatures::known(); if !self.message_handler.route_handler.should_request_full_sync(&peer.transport.get_their_node_id()) { features.clear_initial_routing_sync(); } let resp = msgs::Init { features }; - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.outbound_queue, descriptor, &resp); + peer.transport.enqueue_message(&resp, &mut peer.outbound_queue, &*self.logger); } // Process an incoming Init message and set Peer and PeerManager state accordingly - fn process_init_message(&self, message: Message, descriptor: &Descriptor, peer: &mut Peer, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap) -> Result<(), PeerHandleError> { + fn process_init_message(&self, message: Message, descriptor: &Descriptor, peer: &mut Peer, node_id_to_descriptor: &mut HashMap) -> Result<(), PeerHandleError> { let their_node_id = peer.transport.get_their_node_id(); match message { @@ -731,13 +735,10 @@ impl, peers_needing_send: &mut HashSet, node_id_to_descriptor: &mut HashMap, data: &[u8]) -> Result { + fn do_read_event(&self, peer_descriptor: &mut Descriptor, peer: &mut Peer, node_id_to_descriptor: &mut HashMap, data: &[u8]) -> Result { match peer.transport.process_input(data, &mut peer.outbound_queue) { Err(e) => { @@ -766,13 +767,7 @@ impl 0 { let init_message = received_messages.remove(0); - self.process_init_message(init_message, peer_descriptor, peer, peers_needing_send, node_id_to_descriptor)?; + self.process_init_message(init_message, peer_descriptor, peer, node_id_to_descriptor)?; } for message in received_messages { @@ -802,7 +797,7 @@ impl { log_trace!(self.logger, "Got Err handling message, sending Error message because {}", e.err); - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.outbound_queue, peer_descriptor, &msg); + peer.transport.enqueue_message(&msg, &mut peer.outbound_queue, &*self.logger); continue; }, } @@ -811,7 +806,7 @@ impl { return Err(e) }, MessageHandlingError::LightningError(e) => { @@ -827,9 +822,7 @@ impl, - peers_needing_send: &mut HashSet) -> Result<(), MessageHandlingError> { + peer: &mut Peer) -> Result<(), MessageHandlingError> { let their_node_id = peer.transport.get_their_node_id(); let post_init_state = peer.post_init_state.as_mut().unwrap(); @@ -864,7 +857,7 @@ impl { if msg.ponglen < 65532 { let resp = msgs::Pong { byteslen: msg.ponglen }; - self.enqueue_message(peers_needing_send, &mut peer.transport, &mut peer.outbound_queue, &peer_descriptor, &resp); + peer.transport.enqueue_message(&resp, &mut peer.outbound_queue, &*self.logger); } }, wire::Message::Pong(_msg) => { @@ -1242,11 +1235,8 @@ impl self.do_attempt_write_data(&mut descriptor, &mut peer.post_init_state, &mut peer.transport, &mut peer.outbound_queue), - None => panic!("Inconsistent peers set state!"), - } + for (descriptor, peer) in peers.peers_needing_send() { + self.do_attempt_write_data(&mut descriptor.clone(), &mut peer.post_init_state, &mut peer.transport, &mut peer.outbound_queue); } } } From 41c73743970a8011b03fc7e845fdda1bca093629 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Fri, 4 Sep 2020 13:57:44 -0700 Subject: [PATCH 91/96] Move Conduit decryption into read() This gets rid of the complexity required to handle Iterators that return errors and makes way for fewer copies in the decryption path. --- lightning/src/ln/peers/conduit.rs | 131 +++++---------------- lightning/src/ln/peers/handshake/states.rs | 6 +- lightning/src/ln/peers/transport.rs | 72 ++++------- 3 files changed, 57 insertions(+), 152 deletions(-) diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index ed0b3bd595a..724dd207a84 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -2,6 +2,7 @@ use ln::peers::{chacha, hkdf5869rfc}; use util::byte_utils; +use std::collections::VecDeque; pub(super) type SymmetricKey = [u8; 32]; @@ -33,29 +34,14 @@ pub(super) struct Decryptor { pending_message_length: Option, read_buffer: Option>, - poisoned: bool, // signal an error has occurred so None is returned on iteration after failure + decrypted_payloads: VecDeque>, } impl Iterator for Decryptor { - type Item = Result>, String>; + type Item = Vec; fn next(&mut self) -> Option { - if self.poisoned { - return None; - } - - match self.decrypt_single_message(None) { - Ok(Some(result)) => { - Some(Ok(Some(result))) - }, - Ok(None) => { - None - } - Err(e) => { - self.poisoned = true; - Some(Err(e)) - } - } + self.decrypted_payloads.pop_front() } } @@ -74,7 +60,7 @@ impl Conduit { receiving_nonce: 0, read_buffer: None, pending_message_length: None, - poisoned: false + decrypted_payloads: VecDeque::new(), } } } @@ -84,7 +70,7 @@ impl Conduit { self.encryptor.encrypt(buffer) } - pub(super) fn read(&mut self, data: &[u8]) { + pub(super) fn read(&mut self, data: &[u8]) -> Result<(), String>{ self.decryptor.read(data) } @@ -134,9 +120,25 @@ impl Encryptor { } impl Decryptor { - pub(super) fn read(&mut self, data: &[u8]) { - let read_buffer = self.read_buffer.get_or_insert(Vec::new()); - read_buffer.extend_from_slice(data); + pub(super) fn read(&mut self, data: &[u8]) -> Result<(), String> { + let mut input_data = Some(data); + + loop { + match self.decrypt_single_message(input_data) { + Ok(Some(result)) => { + self.decrypted_payloads.push_back(result); + }, + Ok(None) => { + break; + } + Err(e) => { + return Err(e); + } + } + input_data = None; + } + + Ok(()) } /// Decrypt a single message. If data containing more than one message has been received, @@ -318,7 +320,7 @@ mod tests { let encrypted = remote_peer.encrypt(&[1]); connected_peer.decryptor.receiving_key = [0; 32]; - assert_eq!(connected_peer.decrypt_single_message(Some(&encrypted)), Err("invalid hmac".to_string())); + assert_eq!(connected_peer.read(&encrypted), Err("invalid hmac".to_string())); } // Test next()::None @@ -334,86 +336,9 @@ mod tests { fn decryptor_iterator_one_item_valid() { let (mut connected_peer, mut remote_peer) = setup_peers(); let encrypted = remote_peer.encrypt(&[1]); - connected_peer.read(&encrypted); - - assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); - assert_eq!(connected_peer.decryptor.next(), None); - } - - // Test next()::err -> next()::None - #[test] - fn decryptor_iterator_error() { - let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encrypt(&[1]); - connected_peer.read(&encrypted); - - connected_peer.decryptor.receiving_key = [0; 32]; - assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); - assert_eq!(connected_peer.decryptor.next(), None); - } - - // Test next()::Some -> next()::err -> next()::None - #[test] - fn decryptor_iterator_error_after_success() { - let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encrypt(&[1]); - connected_peer.read(&encrypted); - let encrypted = remote_peer.encrypt(&[2]); - connected_peer.read(&encrypted); - - assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); - connected_peer.decryptor.receiving_key = [0; 32]; - assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); - assert_eq!(connected_peer.decryptor.next(), None); - } - - // Test that next()::Some -> next()::err -> next()::None - // Error should poison decryptor - #[test] - fn decryptor_iterator_next_after_error_returns_none() { - let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encrypt(&[1]); - connected_peer.read(&encrypted); - let encrypted = remote_peer.encrypt(&[2]); - connected_peer.read(&encrypted); - let encrypted = remote_peer.encrypt(&[3]); - connected_peer.read(&encrypted); - - // Get one valid value - assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); - let valid_receiving_key = connected_peer.decryptor.receiving_key; - - // Corrupt the receiving key and ensure we get a failure - connected_peer.decryptor.receiving_key = [0; 32]; - assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); - - // Restore the receiving key, do a read and ensure None is returned (poisoned) - connected_peer.decryptor.receiving_key = valid_receiving_key; - assert_eq!(connected_peer.decryptor.next(), None); - } - - // Test next()::Some -> next()::err -> read() -> next()::None - // Error should poison decryptor even after future reads - #[test] - fn decryptor_iterator_read_next_after_error_returns_none() { - let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encrypt(&[1]); - connected_peer.read(&encrypted); - let encrypted = remote_peer.encrypt(&[2]); - connected_peer.read(&encrypted); - - // Get one valid value - assert_eq!(connected_peer.decryptor.next(), Some(Ok(Some(vec![1])))); - let valid_receiving_key = connected_peer.decryptor.receiving_key; - - // Corrupt the receiving key and ensure we get a failure - connected_peer.decryptor.receiving_key = [0; 32]; - assert_eq!(connected_peer.decryptor.next(), Some(Err("invalid hmac".to_string()))); + connected_peer.read(&encrypted).unwrap(); - // Restore the receiving key, do a read and ensure None is returned (poisoned) - let encrypted = remote_peer.encrypt(&[3]); - connected_peer.read(&encrypted); - connected_peer.decryptor.receiving_key = valid_receiving_key; + assert_eq!(connected_peer.decryptor.next(), Some(vec![1])); assert_eq!(connected_peer.decryptor.next(), None); } } \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 00962346eaa..231db5adbfc 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -386,7 +386,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // Any remaining data in the read buffer would be encrypted, so transfer ownership // to the Conduit for future use. - conduit.read(&input[bytes_read..]); + conduit.read(&input[bytes_read..])?; Ok(( None, @@ -766,7 +766,7 @@ mod test { let test_ctx = TestCtx::new(); let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); let mut act3 = test_ctx.valid_act3; - act3.extend_from_slice(&[2; 100]); + act3.extend_from_slice(&[2; 16]); let (conduit, remote_pubkey) = if let (None, Complete(Some((conduit, remote_pubkey)))) = awaiting_act_three_state.next(&act3).unwrap() { (conduit, remote_pubkey) @@ -775,7 +775,7 @@ mod test { }; assert_eq!(remote_pubkey, test_ctx.initiator_public_key); - assert_eq!(100, conduit.decryptor.read_buffer_length()); + assert_eq!(16, conduit.decryptor.read_buffer_length()); } // Responder::AwaitingActThree -> Error (bad version bytes) diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index b5402a07431..0c715fd9e88 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -88,7 +88,7 @@ impl ITransport for Transport { - conduit.read(input); + conduit.read(input)?; Ok(false) // newly connected } } @@ -102,53 +102,33 @@ impl ITransport for Transport {} Some(ref mut conduit) => { - // Using Iterators that can error requires special handling - // The item returned from next() has type Option, String>> - // The Some wrapper is stripped for each item inside the loop - // There are 3 valid match cases: - // 1) Some(Ok(Some(msg_data))) => Indicates a valid decrypted msg accessed via msg_data - // 2) Some(Err(_)) => Indicates an error during decryption that should be handled - // 3) None -> Indicates there were no messages available to decrypt - // Invalid Cases - // 1) Some(Ok(None)) => Translated to None case above so users of iterators can stop correctly - for msg_data_result in &mut conduit.decryptor { - match msg_data_result { - Ok(Some(msg_data)) => { - let mut reader = ::std::io::Cursor::new(&msg_data[..]); - let message_result = wire::read(&mut reader); - let message = match message_result { - Ok(x) => x, - Err(e) => { - match e { - msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::UnknownRequiredFeature => { - log_debug!(logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); - continue; - } - msgs::DecodeError::InvalidValue => { - log_debug!(logger, "Got an invalid value while deserializing message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::ShortRead => { - log_debug!(logger, "Deserialization failed due to shortness of message"); - return Err(PeerHandleError { no_connection_possible: false }); - } - msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), - msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), - } - } - }; - - received_messages.push(message); - }, + for msg_data in &mut conduit.decryptor { + let mut reader = ::std::io::Cursor::new(&msg_data[..]); + let message_result = wire::read(&mut reader); + let message = match message_result { + Ok(x) => x, Err(e) => { - log_trace!(logger, "Message decryption failed due to: {}", e); - return Err(PeerHandleError { no_connection_possible: false }); - } - Ok(None) => { - panic!("Invalid behavior. Conduit iterator should never return this match.") + match e { + msgs::DecodeError::UnknownVersion => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::UnknownRequiredFeature => { + log_debug!(logger, "Got a channel/node announcement with an known required feature flag, you may want to update!"); + continue; + } + msgs::DecodeError::InvalidValue => { + log_debug!(logger, "Got an invalid value while deserializing message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::ShortRead => { + log_debug!(logger, "Deserialization failed due to shortness of message"); + return Err(PeerHandleError { no_connection_possible: false }); + } + msgs::DecodeError::BadLengthDescriptor => return Err(PeerHandleError { no_connection_possible: false }), + msgs::DecodeError::Io(_) => return Err(PeerHandleError { no_connection_possible: false }), + } } - } + }; + + received_messages.push(message); } } } From 810b491a0ddb54c64a402df14988899c72422362 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Tue, 8 Sep 2020 12:48:18 -0700 Subject: [PATCH 92/96] perf: Decryptor can now read from input slice when appropriate Previously, all input data was written to the read buffer before any decryption was attempted. This patch will use the input data solely in the event that there is no previous data in the internal read buffer. This also converts all tests to use the public interface instead of the previously used decrypt_single_message This was design feedback from the original 494 review. --- fuzz/src/peer_crypt.rs | 20 ++++-- lightning/src/ln/peers/conduit.rs | 116 +++++++++++++++++++----------- 2 files changed, 88 insertions(+), 48 deletions(-) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index 76ccc18fbe6..b60bf086478 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -118,23 +118,33 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re // randomly choose sender of message let receiver_unencrypted_msg = if generator.generate_bool()? { let encrypted_msg = initiator_conduit.encrypt(sender_unencrypted_msg); - if let Ok(msg) = responder_conduit.decrypt_single_message(Some(&encrypted_msg)) { - msg + if let Ok(_) = responder_conduit.decryptor.read(&encrypted_msg) { + if let Some(msg) = responder_conduit.decryptor.next() { + msg + } else { + assert!(failures_expected); + return Ok(()); + } } else { assert!(failures_expected); return Ok(()); } } else { let encrypted_msg = responder_conduit.encrypt(sender_unencrypted_msg); - if let Ok(msg) = initiator_conduit.decrypt_single_message(Some(&encrypted_msg)) { - msg + if let Ok(_) = initiator_conduit.decryptor.read(&encrypted_msg) { + if let Some(msg) = initiator_conduit.decryptor.next() { + msg + } else { + assert!(failures_expected); + return Ok(()); + } } else { assert!(failures_expected); return Ok(()); } }; - assert_eq!(sender_unencrypted_msg, receiver_unencrypted_msg.unwrap().as_slice()); + assert_eq!(sender_unencrypted_msg, receiver_unencrypted_msg.as_slice()); } } diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 724dd207a84..6bee7d6ca04 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -17,7 +17,11 @@ const KEY_ROTATION_INDEX: u32 = 1000; /// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering. pub struct Conduit { pub(super) encryptor: Encryptor, - pub(super) decryptor: Decryptor + + #[cfg(feature = "fuzztarget")] + pub decryptor: Decryptor, + #[cfg(not(feature = "fuzztarget"))] + pub(super) decryptor: Decryptor, } @@ -27,7 +31,7 @@ pub(super) struct Encryptor { sending_nonce: u32, } -pub(super) struct Decryptor { +pub struct Decryptor { receiving_key: SymmetricKey, receiving_chaining_key: SymmetricKey, receiving_nonce: u32, @@ -58,7 +62,7 @@ impl Conduit { receiving_key, receiving_chaining_key: chaining_key, receiving_nonce: 0, - read_buffer: None, + read_buffer: Some(vec![]), pending_message_length: None, decrypted_payloads: VecDeque::new(), } @@ -74,15 +78,6 @@ impl Conduit { self.decryptor.read(data) } - /// Decrypt a single message. If data containing more than one message has been received, - /// only the first message will be returned, and the rest stored in the internal buffer. - /// If a message pending in the buffer still hasn't been decrypted, that message will be - /// returned in lieu of anything new, even if new data is provided. - #[cfg(any(test, feature = "fuzztarget"))] - pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Result>, String> { - Ok(self.decryptor.decrypt_single_message(new_data)?) - } - fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { *nonce += 1; if *nonce == KEY_ROTATION_INDEX { @@ -120,49 +115,44 @@ impl Encryptor { } impl Decryptor { - pub(super) fn read(&mut self, data: &[u8]) -> Result<(), String> { - let mut input_data = Some(data); + // Read in new encrypted data and process it. This attempts to decrypt the input data and any + // existing data in the internal read buffer and can return an error if there is an error raised + // from the decryption code. + pub fn read(&mut self, data: &[u8]) -> Result<(), String> { + let mut read_buffer = self.read_buffer.take().unwrap(); + + let buffer = if read_buffer.is_empty() { + data + } else { + read_buffer.extend_from_slice(data); + read_buffer.as_slice() + }; + + let mut read_offset = 0; loop { - match self.decrypt_single_message(input_data) { - Ok(Some(result)) => { + match self.decrypt_next(&buffer[read_offset..]) { + Ok((Some(result), bytes_read)) => { + read_offset += bytes_read; self.decrypted_payloads.push_back(result); }, - Ok(None) => { + Ok((None, 0)) => { + self.read_buffer = Some(buffer[read_offset..].to_vec()); break; } Err(e) => { return Err(e); } + Ok((None, _)) => { panic!("Invalid return from decrypt_next()") } } - input_data = None; } Ok(()) } - /// Decrypt a single message. If data containing more than one message has been received, - /// only the first message will be returned, and the rest stored in the internal buffer. - /// If a message pending in the buffer still hasn't been decrypted, that message will be - /// returned in lieu of anything new, even if new data is provided. - pub fn decrypt_single_message(&mut self, new_data: Option<&[u8]>) -> Result>, String> { - let mut read_buffer = if let Some(buffer) = self.read_buffer.take() { - buffer - } else { - Vec::new() - }; - - if let Some(data) = new_data { - read_buffer.extend_from_slice(data); - } - - let (current_message, offset) = self.decrypt(&read_buffer[..])?; - read_buffer.drain(..offset); // drain the read buffer - self.read_buffer = Some(read_buffer); // assign the new value to the built-in buffer - Ok(current_message) - } - - fn decrypt(&mut self, buffer: &[u8]) -> Result<(Option>, usize), String> { + // Decrypt the next payload from the slice returning the number of bytes consumed during the + // operation. This will always be (None, 0) if no payload could be decrypted. + fn decrypt_next(&mut self, buffer: &[u8]) -> Result<(Option>, usize), String> { let message_length = if let Some(length) = self.pending_message_length { // we have already decrypted the header length @@ -249,10 +239,47 @@ mod tests { let encrypted_message = connected_peer.encrypt(&message); assert_eq!(encrypted_message.len(), 2 + 16 + 16); - let decrypted_message = remote_peer.decrypt_single_message(Some(&encrypted_message)).unwrap().unwrap(); + remote_peer.decryptor.read(&encrypted_message[..]).unwrap(); + let decrypted_message = remote_peer.decryptor.next().unwrap(); assert_eq!(decrypted_message, vec![]); } + // Test that descrypting from a slice that is the partial data followed by another decrypt call + // with the remaining data works. This exercises the slow-path for decryption and ensures the + // data is written to the read_buffer properly. + #[test] + fn test_decrypt_from_slice_two_calls_no_header_then_rest() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + + let message: Vec = vec![1]; + let encrypted_message = connected_peer.encrypt(&message); + + remote_peer.decryptor.read(&encrypted_message[..1]).unwrap(); + assert!(remote_peer.decryptor.next().is_none()); + + remote_peer.decryptor.read(&encrypted_message[1..]).unwrap(); + let decrypted_message = remote_peer.decryptor.next().unwrap(); + + assert_eq!(decrypted_message, vec![1]); + } + + // Include the header in the first slice + #[test] + fn test_decrypt_from_slice_two_calls_header_then_rest() { + let (mut connected_peer, mut remote_peer) = setup_peers(); + + let message: Vec = vec![1]; + let encrypted_message = connected_peer.encrypt(&message); + + remote_peer.decryptor.read(&encrypted_message[..20]).unwrap(); + assert!(remote_peer.decryptor.next().is_none()); + + remote_peer.decryptor.read(&encrypted_message[20..]).unwrap(); + let decrypted_message = remote_peer.decryptor.next().unwrap(); + + assert_eq!(decrypted_message, vec![1]); + } + #[test] fn test_nonce_chaining() { let (mut connected_peer, _remote_peer) = setup_peers(); @@ -302,13 +329,16 @@ mod tests { let mut current_encrypted_message = encrypted_messages.remove(0); let next_encrypted_message = encrypted_messages.remove(0); current_encrypted_message.extend_from_slice(&next_encrypted_message); - let decrypted_message = remote_peer.decrypt_single_message(Some(¤t_encrypted_message)).unwrap().unwrap(); + remote_peer.read(¤t_encrypted_message[..]).unwrap(); + + let decrypted_message = remote_peer.decryptor.next().unwrap(); assert_eq!(decrypted_message, message); } for _ in 0..501 { // decrypt messages directly from buffer without adding to it - let decrypted_message = remote_peer.decrypt_single_message(None).unwrap().unwrap(); + remote_peer.read(&[]).unwrap(); + let decrypted_message = remote_peer.decryptor.next().unwrap(); assert_eq!(decrypted_message, message); } } From 6b4e8bbea2b3885dbad389c287cda27c19433275 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 9 Sep 2020 08:33:23 -0700 Subject: [PATCH 93/96] refactor: Use a real struct instead of conduit_and_remote_pubkey tuple This makes the process_act() interface a bit cleaner on a successfully completed handshake. --- fuzz/src/peer_crypt.rs | 30 +++++++-------- lightning/src/ln/peers/handshake/mod.rs | 22 +++++++---- lightning/src/ln/peers/handshake/states.rs | 44 +++++++++++++--------- lightning/src/ln/peers/test_util.rs | 14 +++++-- lightning/src/ln/peers/transport.rs | 12 +++--- 5 files changed, 72 insertions(+), 50 deletions(-) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index b60bf086478..a955ef2208d 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -157,15 +157,15 @@ fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorF // The handshake should complete with any valid private keys let act2 = test_ctx.responder_handshake.process_act(&test_ctx.act1).unwrap().0.unwrap(); let (act3, (mut initiator_conduit, responder_pubkey)) = match test_ctx.initiator_handshake.process_act(&act2) { - Ok((Some(act3), Some((conduit, remote_pubkey)))) => { - (act3, (conduit, remote_pubkey)) + Ok((Some(act3), Some(completed_handshake_info))) => { + (act3, (completed_handshake_info.conduit, completed_handshake_info.their_node_id)) } _ => panic!("handshake failed") }; let (mut responder_conduit, initiator_pubkey) = match test_ctx.responder_handshake.process_act(&act3) { - Ok((None, Some((conduit, remote_pubkey)))) => { - (conduit, remote_pubkey) + Ok((None, Some(completed_handshake_info))) => { + (completed_handshake_info.conduit, completed_handshake_info.their_node_id) } _ => panic!("handshake failed") }; @@ -256,12 +256,12 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr let act2_chunks = split_vec(generator, &act2)?; let mut act3_option = None; - let mut conduit_and_remote_pubkey_option = None; + let mut initiator_completed_handshake_info_option = None; for partial_act2 in act2_chunks { match test_ctx.initiator_handshake.process_act(&partial_act2) { - Ok((Some(act3), Some(conduit_and_remote_pubkey_option_inner))) => { + Ok((Some(act3), Some(completed_handshake_info_option_inner))) => { act3_option = Some(act3); - conduit_and_remote_pubkey_option = Some(conduit_and_remote_pubkey_option_inner); + initiator_completed_handshake_info_option = Some(completed_handshake_info_option_inner); // Valid conduit and pubkey indicates handshake is over break; @@ -279,7 +279,7 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr // Ensure we actually received act3 bytes, conduit, and remote pubkey from process_act() let act3 = act3_option.unwrap(); - let (mut initiator_conduit, responder_pubkey) = conduit_and_remote_pubkey_option.unwrap(); + let mut initiator_completed_handshake_info = initiator_completed_handshake_info_option.unwrap(); // Possibly generate bad data for act3 let (mut act3, is_bad_data) = maybe_generate_bad_act(generator, act3)?; @@ -293,11 +293,11 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr // Split act3 into between 1..7 chunks let act3_chunks = split_vec(generator, &act3)?; - let mut conduit_and_remote_pubkey_option = None; + let mut responder_completed_handshake_info = None; for partial_act3 in act3_chunks { match test_ctx.responder_handshake.process_act(&partial_act3) { - Ok((None, Some(conduit_and_remote_pubkey_option_inner))) => { - conduit_and_remote_pubkey_option = Some(conduit_and_remote_pubkey_option_inner); + Ok((None, Some(completed_handshake_info_inner))) => { + responder_completed_handshake_info = Some(completed_handshake_info_inner); // Valid conduit and pubkey indicates handshake is over break; @@ -313,20 +313,20 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr }; } // Ensure we actually received conduit and remote pubkey from process_act() - let (mut responder_conduit, initiator_pubkey) = conduit_and_remote_pubkey_option.unwrap(); + let mut responder_completed_handshake_info = responder_completed_handshake_info.unwrap(); // The handshake should complete with each peer knowing the static_public_key of the remote peer - if initiator_pubkey != test_ctx.initiator_static_public_key { + if responder_completed_handshake_info.their_node_id != test_ctx.initiator_static_public_key { assert!(used_generated_data); return Ok(()); } - if responder_pubkey != test_ctx.responder_static_public_key { + if initiator_completed_handshake_info.their_node_id != test_ctx.responder_static_public_key { assert!(used_generated_data); return Ok(()); } // The nodes should be able to communicate over the conduit - do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit, used_generated_data) + do_conduit_tests(generator, &mut initiator_completed_handshake_info.conduit, &mut responder_completed_handshake_info.conduit, used_generated_data) } #[inline] diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 340e0996e86..4f9ee039b60 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -27,6 +27,12 @@ pub struct PeerHandshake { ready_to_process: bool, } +/// Container for the information returned from a successfully completed handshake +pub struct CompletedHandshakeInfo { + pub conduit: Conduit, + pub their_node_id: PublicKey, +} + impl IPeerHandshake for PeerHandshake { /// Instantiate a handshake given the peer's static public key. The ephemeral private key MUST /// generate a new session with strong cryptographic randomness. @@ -66,8 +72,8 @@ impl IPeerHandshake for PeerHandshake { /// # Return values /// Returns a tuple with the following components: /// `.0`: Byte vector containing the next act to send back to the peer per the handshake protocol - /// `.1`: Some(Conduit, PublicKey) if the handshake was just processed to completion and messages can now be encrypted and decrypted - fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + /// `.1`: Some(CompleteHandshakeInfo) if the handshake was just processed to completion and messages can now be encrypted and decrypted + fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option), String> { assert!(self.ready_to_process); let cur_state = self.state.take().unwrap(); @@ -77,8 +83,8 @@ impl IPeerHandshake for PeerHandshake { }; let result = match next_state { - HandshakeState::Complete(ref mut conduit_and_pubkey) => { - Ok((act_option, conduit_and_pubkey.take())) + HandshakeState::Complete(ref mut complete_handshake_info) => { + Ok((act_option, complete_handshake_info.take())) }, _ => { Ok((act_option, None)) } }; @@ -188,14 +194,14 @@ mod test { let mut test_ctx = TestCtx::new(); let act2 = do_process_act_or_panic!(test_ctx.inbound_handshake, &test_ctx.act1); - let (act3, inbound_remote_pubkey) = if let (Some(act3), Some((_, remote_pubkey))) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { - (act3, remote_pubkey) + let (act3, inbound_remote_pubkey) = if let (Some(act3), Some(completed_handshake_info)) = test_ctx.outbound_handshake.process_act(&act2).unwrap() { + (act3, completed_handshake_info.their_node_id) } else { panic!(); }; - let outbound_remote_pubkey = if let (None, Some((_, remote_pubkey))) = test_ctx.inbound_handshake.process_act(&act3).unwrap() { - remote_pubkey + let outbound_remote_pubkey = if let (None, Some(completed_handshake_info)) = test_ctx.inbound_handshake.process_act(&act3).unwrap() { + completed_handshake_info.their_node_id } else { panic!(); }; diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 231db5adbfc..2afd2c92614 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -7,7 +7,7 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::{chacha, hkdf5869rfc}; use ln::peers::conduit::{Conduit, SymmetricKey}; use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; -use ln::peers::handshake::IHandshakeState; +use ln::peers::handshake::{CompletedHandshakeInfo, IHandshakeState}; // Alias type to help differentiate between temporary key and chaining key when passing bytes around type ChainingKey = [u8; 32]; @@ -28,7 +28,7 @@ pub(super) enum HandshakeState { ResponderAwaitingActOne(ResponderAwaitingActOneState), InitiatorAwaitingActTwo(InitiatorAwaitingActTwoState), ResponderAwaitingActThree(ResponderAwaitingActThreeState), - Complete(Option<(Conduit, PublicKey)>), + Complete(Option), } // Enum dispatch for state machine. Single public interface can statically dispatch to all states @@ -48,7 +48,7 @@ impl IHandshakeState for HandshakeState { HandshakeState::ResponderAwaitingActOne(state) => { state.next(input) }, HandshakeState::InitiatorAwaitingActTwo(state) => { state.next(input) }, HandshakeState::ResponderAwaitingActThree(state) => { state.next(input) }, - HandshakeState::Complete(_conduit) => { panic!("no acts left to process") } + HandshakeState::Complete(_completed_handshake_info) => { panic!("no acts left to process") } } } } @@ -310,7 +310,12 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { act_three[0] = 0; Ok(( Some(Act::Three(act_three)), - HandshakeState::Complete(Some((conduit, responder_static_public_key))) + HandshakeState::Complete(Some( + CompletedHandshakeInfo { + conduit, + their_node_id: responder_static_public_key + } + )) )) } } @@ -390,7 +395,12 @@ impl IHandshakeState for ResponderAwaitingActThreeState { Ok(( None, - HandshakeState::Complete(Some((conduit, initiator_pubkey))) + HandshakeState::Complete(Some( + CompletedHandshakeInfo { + conduit, + their_node_id: initiator_pubkey + } + )) )) } } @@ -681,15 +691,15 @@ mod test { let (_act1, awaiting_act_two_state) = do_next_or_panic!(test_ctx.initiator, &[]); let (act3, complete_state) = do_next_or_panic!(awaiting_act_two_state, &test_ctx.valid_act2); - let (conduit, remote_pubkey) = if let Complete(Some((conduit, remote_pubkey))) = complete_state { - (conduit, remote_pubkey) + let completed_handshake_info = if let Complete(Some(completed_handshake_info)) = complete_state { + completed_handshake_info } else { panic!(); }; assert_eq!(act3.as_ref(), test_ctx.valid_act3.as_slice()); - assert_eq!(remote_pubkey, test_ctx.responder_static_public_key); - assert_eq!(0, conduit.decryptor.read_buffer_length()); + assert_eq!(completed_handshake_info.their_node_id, test_ctx.responder_static_public_key); + assert_eq!(0, completed_handshake_info.conduit.decryptor.read_buffer_length()); } // Initiator::AwaitingActTwo -> Complete (segmented calls) @@ -748,14 +758,14 @@ mod test { let test_ctx = TestCtx::new(); let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); - let (conduit, remote_pubkey) = if let (None, Complete(Some((conduit, remote_pubkey)))) = awaiting_act_three_state.next(&test_ctx.valid_act3).unwrap() { - (conduit, remote_pubkey) + let completed_handshake_info = if let (None, Complete(Some(completed_handshake_info))) = awaiting_act_three_state.next(&test_ctx.valid_act3).unwrap() { + completed_handshake_info } else { panic!(); }; - assert_eq!(remote_pubkey, test_ctx.initiator_public_key); - assert_eq!(0, conduit.decryptor.read_buffer_length()); + assert_eq!(completed_handshake_info.their_node_id, test_ctx.initiator_public_key); + assert_eq!(0, completed_handshake_info.conduit.decryptor.read_buffer_length()); } // Responder::AwaitingActThree -> None (with extra bytes) @@ -768,14 +778,14 @@ mod test { let mut act3 = test_ctx.valid_act3; act3.extend_from_slice(&[2; 16]); - let (conduit, remote_pubkey) = if let (None, Complete(Some((conduit, remote_pubkey)))) = awaiting_act_three_state.next(&act3).unwrap() { - (conduit, remote_pubkey) + let completed_handshake_info = if let (None, Complete(Some(completed_handshake_info))) = awaiting_act_three_state.next(&act3).unwrap() { + completed_handshake_info } else { panic!(); }; - assert_eq!(remote_pubkey, test_ctx.initiator_public_key); - assert_eq!(16, conduit.decryptor.read_buffer_length()); + assert_eq!(completed_handshake_info.their_node_id, test_ctx.initiator_public_key); + assert_eq!(16, completed_handshake_info.conduit.decryptor.read_buffer_length()); } // Responder::AwaitingActThree -> Error (bad version bytes) diff --git a/lightning/src/ln/peers/test_util.rs b/lightning/src/ln/peers/test_util.rs index afe4b9d8995..539f83265d6 100644 --- a/lightning/src/ln/peers/test_util.rs +++ b/lightning/src/ln/peers/test_util.rs @@ -5,6 +5,7 @@ use bitcoin::secp256k1::key::{PublicKey, SecretKey}; use ln::peers::conduit::Conduit; use ln::peers::handler::{SocketDescriptor, ITransport, PeerHandleError, MessageQueuer}; +use ln::peers::handshake::CompletedHandshakeInfo; use ln::peers::transport::{IPeerHandshake, PayloadQueuer}; use std::rc::Rc; @@ -42,7 +43,7 @@ impl IPeerHandshake for PeerHandshakeTestStubFail { PeerHandshakeTestStubFail { } } - fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option), String> { Err("Oh no!".to_string()) } } @@ -68,7 +69,7 @@ impl IPeerHandshake for PeerHandshakeTestStubBytes { PeerHandshakeTestStubBytes { } } - fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option), String> { Ok((Some(Self::RETURNED_BYTES[..].to_vec()), None)) } } @@ -89,13 +90,18 @@ impl IPeerHandshake for PeerHandshakeTestStubComplete { PeerHandshakeTestStubComplete { } } - fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String> { + fn process_act(&mut self, _input: &[u8]) -> Result<(Option>, Option), String> { let curve = secp256k1::Secp256k1::new(); let private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); let public_key = PublicKey::from_secret_key(&curve, &private_key); let conduit = Conduit::new([0;32], [0;32], [0;32]); - Ok((None, Some((conduit, public_key)))) + Ok((None, Some( + CompletedHandshakeInfo { + conduit, + their_node_id: public_key + } + ))) } } diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index 0c715fd9e88..679adcb5942 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -4,7 +4,7 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::conduit::Conduit; use ln::peers::handler::{ITransport, PeerHandleError, MessageQueuer}; -use ln::peers::handshake::PeerHandshake; +use ln::peers::handshake::{CompletedHandshakeInfo, PeerHandshake}; use ln::{wire, msgs}; use ln::wire::{Encode, Message}; @@ -25,7 +25,7 @@ pub trait IPeerHandshake { /// Progress the handshake given bytes received from the peer. Returns Some(Conduit, PublicKey) when the handshake /// is complete. - fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option<(Conduit, PublicKey)>), String>; + fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option), String>; } /// Trait representing a container that allows enqueuing of Vec<[u8]> @@ -71,7 +71,7 @@ impl ITransport for Transport { - let (response_option, conduit_and_remote_pubkey_option) = self.handshake.process_act(input)?; + let (response_option, completed_handshake_info_option) = self.handshake.process_act(input)?; // Any response generated by the handshake sequence is put into the response buffer if let Some(response) = response_option { @@ -79,9 +79,9 @@ impl ITransport for Transport Date: Wed, 9 Sep 2020 08:46:29 -0700 Subject: [PATCH 94/96] refactor: Make Conduit a simple wrapper The public interface was in a half-state with some callers referencing the Decryptor directly for message iteration and others using the public interface for the encryption path. This patch moves everything to using the Encryptor and Decryptor directly. This is motivated by feedback from 494, that recommended the objects are split up but still have common functions for the key rotation. --- fuzz/src/peer_crypt.rs | 4 +- lightning/src/ln/peers/conduit.rs | 47 ++++++++-------------- lightning/src/ln/peers/handshake/states.rs | 2 +- lightning/src/ln/peers/transport.rs | 4 +- 4 files changed, 21 insertions(+), 36 deletions(-) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index a955ef2208d..2827e2be98a 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -117,7 +117,7 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re // randomly choose sender of message let receiver_unencrypted_msg = if generator.generate_bool()? { - let encrypted_msg = initiator_conduit.encrypt(sender_unencrypted_msg); + let encrypted_msg = initiator_conduit.encryptor.encrypt(sender_unencrypted_msg); if let Ok(_) = responder_conduit.decryptor.read(&encrypted_msg) { if let Some(msg) = responder_conduit.decryptor.next() { msg @@ -130,7 +130,7 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re return Ok(()); } } else { - let encrypted_msg = responder_conduit.encrypt(sender_unencrypted_msg); + let encrypted_msg = responder_conduit.encryptor.encrypt(sender_unencrypted_msg); if let Ok(_) = initiator_conduit.decryptor.read(&encrypted_msg) { if let Some(msg) = initiator_conduit.decryptor.next() { msg diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 6bee7d6ca04..602390eaff2 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -14,18 +14,12 @@ const KEY_ROTATION_INDEX: u32 = 1000; /// Returned after a successful handshake to encrypt and decrypt communication with peer nodes. /// It should not normally be manually instantiated. /// Automatically handles key rotation. -/// For decryption, it is recommended to call `decrypt_message_stream` for automatic buffering. pub struct Conduit { - pub(super) encryptor: Encryptor, - - #[cfg(feature = "fuzztarget")] + pub encryptor: Encryptor, pub decryptor: Decryptor, - #[cfg(not(feature = "fuzztarget"))] - pub(super) decryptor: Decryptor, - } -pub(super) struct Encryptor { +pub struct Encryptor { sending_key: SymmetricKey, sending_chaining_key: SymmetricKey, sending_nonce: u32, @@ -69,15 +63,6 @@ impl Conduit { } } - /// Encrypt data to be sent to peer - pub fn encrypt(&mut self, buffer: &[u8]) -> Vec { - self.encryptor.encrypt(buffer) - } - - pub(super) fn read(&mut self, data: &[u8]) -> Result<(), String>{ - self.decryptor.read(data) - } - fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { *nonce += 1; if *nonce == KEY_ROTATION_INDEX { @@ -94,7 +79,7 @@ impl Conduit { } impl Encryptor { - pub(super) fn encrypt(&mut self, buffer: &[u8]) -> Vec { + pub fn encrypt(&mut self, buffer: &[u8]) -> Vec { let length = buffer.len() as u16; let length_bytes = byte_utils::be16_to_array(length); @@ -236,7 +221,7 @@ mod tests { let (mut connected_peer, mut remote_peer) = setup_peers(); let message: Vec = vec![]; - let encrypted_message = connected_peer.encrypt(&message); + let encrypted_message = connected_peer.encryptor.encrypt(&message); assert_eq!(encrypted_message.len(), 2 + 16 + 16); remote_peer.decryptor.read(&encrypted_message[..]).unwrap(); @@ -252,7 +237,7 @@ mod tests { let (mut connected_peer, mut remote_peer) = setup_peers(); let message: Vec = vec![1]; - let encrypted_message = connected_peer.encrypt(&message); + let encrypted_message = connected_peer.encryptor.encrypt(&message); remote_peer.decryptor.read(&encrypted_message[..1]).unwrap(); assert!(remote_peer.decryptor.next().is_none()); @@ -269,7 +254,7 @@ mod tests { let (mut connected_peer, mut remote_peer) = setup_peers(); let message: Vec = vec![1]; - let encrypted_message = connected_peer.encrypt(&message); + let encrypted_message = connected_peer.encryptor.encrypt(&message); remote_peer.decryptor.read(&encrypted_message[..20]).unwrap(); assert!(remote_peer.decryptor.next().is_none()); @@ -285,11 +270,11 @@ mod tests { let (mut connected_peer, _remote_peer) = setup_peers(); let message = hex::decode("68656c6c6f").unwrap(); - let encrypted_message = connected_peer.encrypt(&message); + let encrypted_message = connected_peer.encryptor.encrypt(&message); assert_eq!(encrypted_message, hex::decode("cf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95").unwrap()); // the second time the same message is encrypted, the ciphertext should be different - let encrypted_message = connected_peer.encrypt(&message); + let encrypted_message = connected_peer.encryptor.encrypt(&message); assert_eq!(encrypted_message, hex::decode("72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1").unwrap()); } @@ -302,7 +287,7 @@ mod tests { let mut encrypted_messages: Vec> = Vec::new(); for _ in 0..1002 { - let encrypted_message = connected_peer.encrypt(&message); + let encrypted_message = connected_peer.encryptor.encrypt(&message); encrypted_messages.push(encrypted_message); } @@ -320,7 +305,7 @@ mod tests { let mut encrypted_messages: Vec> = Vec::new(); for _ in 0..1002 { - let encrypted_message = connected_peer.encrypt(&message); + let encrypted_message = connected_peer.encryptor.encrypt(&message); encrypted_messages.push(encrypted_message); } @@ -329,7 +314,7 @@ mod tests { let mut current_encrypted_message = encrypted_messages.remove(0); let next_encrypted_message = encrypted_messages.remove(0); current_encrypted_message.extend_from_slice(&next_encrypted_message); - remote_peer.read(¤t_encrypted_message[..]).unwrap(); + remote_peer.decryptor.read(¤t_encrypted_message[..]).unwrap(); let decrypted_message = remote_peer.decryptor.next().unwrap(); assert_eq!(decrypted_message, message); @@ -337,7 +322,7 @@ mod tests { for _ in 0..501 { // decrypt messages directly from buffer without adding to it - remote_peer.read(&[]).unwrap(); + remote_peer.decryptor.read(&[]).unwrap(); let decrypted_message = remote_peer.decryptor.next().unwrap(); assert_eq!(decrypted_message, message); } @@ -347,10 +332,10 @@ mod tests { #[test] fn decryption_failure_errors() { let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encrypt(&[1]); + let encrypted = remote_peer.encryptor.encrypt(&[1]); connected_peer.decryptor.receiving_key = [0; 32]; - assert_eq!(connected_peer.read(&encrypted), Err("invalid hmac".to_string())); + assert_eq!(connected_peer.decryptor.read(&encrypted), Err("invalid hmac".to_string())); } // Test next()::None @@ -365,8 +350,8 @@ mod tests { #[test] fn decryptor_iterator_one_item_valid() { let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encrypt(&[1]); - connected_peer.read(&encrypted).unwrap(); + let encrypted = remote_peer.encryptor.encrypt(&[1]); + connected_peer.decryptor.read(&encrypted).unwrap(); assert_eq!(connected_peer.decryptor.next(), Some(vec![1])); assert_eq!(connected_peer.decryptor.next(), None); diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 2afd2c92614..c038fc7ed8f 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -391,7 +391,7 @@ impl IHandshakeState for ResponderAwaitingActThreeState { // Any remaining data in the read buffer would be encrypted, so transfer ownership // to the Conduit for future use. - conduit.read(&input[bytes_read..])?; + conduit.decryptor.read(&input[bytes_read..])?; Ok(( None, diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index 679adcb5942..a750fb7237e 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -88,7 +88,7 @@ impl ITransport for Transport { - conduit.read(input)?; + conduit.decryptor.read(input)?; Ok(false) // newly connected } } @@ -157,7 +157,7 @@ impl MessageQueuer for Transport Date: Wed, 9 Sep 2020 09:33:17 -0700 Subject: [PATCH 95/96] refactor: Remove Conduit object Now that the CompletedHandshakeInfo exists to pass the relevant pieces out of the handshake code and all users go to the Encryptor and Decryptor directly, this is no longer needed. --- fuzz/src/peer_crypt.rs | 61 ++++---- lightning/src/ln/peers/conduit.rs | 161 ++++++++++----------- lightning/src/ln/peers/handshake/mod.rs | 7 +- lightning/src/ln/peers/handshake/states.rs | 26 ++-- lightning/src/ln/peers/test_util.rs | 7 +- lightning/src/ln/peers/transport.rs | 39 +++-- 6 files changed, 146 insertions(+), 155 deletions(-) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index 2827e2be98a..c65c381a432 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -4,8 +4,7 @@ use std::{error, fmt}; use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey,SecretKey}; -use lightning::ln::peers::conduit::Conduit; -use lightning::ln::peers::handshake::PeerHandshake; +use lightning::ln::peers::handshake::{CompletedHandshakeInfo, PeerHandshake}; use lightning::ln::peers::transport::IPeerHandshake; use utils::test_logger; @@ -102,10 +101,13 @@ impl TestCtx { } } -// Common test function that sends encrypted messages between two conduits until the source data -// runs out. +// Common test function that sends encrypted messages between an encryptor/decryptor until the source +// data runs out. #[inline] -fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, responder_conduit: &mut Conduit, failures_expected: bool) -> Result<(), GeneratorFinishedError> { +fn do_encrypted_communication_tests(generator: &mut FuzzGen, + initiator_completed_handshake_info: &mut CompletedHandshakeInfo, + responder_completed_handshake_info: &mut CompletedHandshakeInfo, + failures_expected: bool) -> Result<(), GeneratorFinishedError> { // Keep sending messages back and forth until the input data is consumed loop { // Randomly generate message length @@ -117,9 +119,9 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re // randomly choose sender of message let receiver_unencrypted_msg = if generator.generate_bool()? { - let encrypted_msg = initiator_conduit.encryptor.encrypt(sender_unencrypted_msg); - if let Ok(_) = responder_conduit.decryptor.read(&encrypted_msg) { - if let Some(msg) = responder_conduit.decryptor.next() { + let encrypted_msg = initiator_completed_handshake_info.encryptor.encrypt(sender_unencrypted_msg); + if let Ok(_) = responder_completed_handshake_info.decryptor.read(&encrypted_msg) { + if let Some(msg) = responder_completed_handshake_info.decryptor.next() { msg } else { assert!(failures_expected); @@ -130,9 +132,9 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re return Ok(()); } } else { - let encrypted_msg = responder_conduit.encryptor.encrypt(sender_unencrypted_msg); - if let Ok(_) = initiator_conduit.decryptor.read(&encrypted_msg) { - if let Some(msg) = initiator_conduit.decryptor.next() { + let encrypted_msg = responder_completed_handshake_info.encryptor.encrypt(sender_unencrypted_msg); + if let Ok(_) = initiator_completed_handshake_info.decryptor.read(&encrypted_msg) { + if let Some(msg) = initiator_completed_handshake_info.decryptor.next() { msg } else { assert!(failures_expected); @@ -149,33 +151,34 @@ fn do_conduit_tests(generator: &mut FuzzGen, initiator_conduit: &mut Conduit, re } // This test completes a valid handshake based on "random" private keys and then sends variable -// length encrypted messages between two conduits to validate that they can communicate. +// length encrypted messages between the local and remote encryptor/decryptor to verify they can +// communicate. #[inline] fn do_completed_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedError> { let mut test_ctx = TestCtx::make(generator)?; // The handshake should complete with any valid private keys let act2 = test_ctx.responder_handshake.process_act(&test_ctx.act1).unwrap().0.unwrap(); - let (act3, (mut initiator_conduit, responder_pubkey)) = match test_ctx.initiator_handshake.process_act(&act2) { + let (act3, mut initiator_completed_handshake_info) = match test_ctx.initiator_handshake.process_act(&act2) { Ok((Some(act3), Some(completed_handshake_info))) => { - (act3, (completed_handshake_info.conduit, completed_handshake_info.their_node_id)) + (act3, completed_handshake_info) } _ => panic!("handshake failed") }; - let (mut responder_conduit, initiator_pubkey) = match test_ctx.responder_handshake.process_act(&act3) { + let mut responder_completed_handshake_info = match test_ctx.responder_handshake.process_act(&act3) { Ok((None, Some(completed_handshake_info))) => { - (completed_handshake_info.conduit, completed_handshake_info.their_node_id) + completed_handshake_info } _ => panic!("handshake failed") }; // The handshake should complete with each peer knowing the static_public_key of the remote peer - assert_eq!(initiator_pubkey, test_ctx.initiator_static_public_key); - assert_eq!(responder_pubkey, test_ctx.responder_static_public_key); + assert_eq!(responder_completed_handshake_info.their_node_id, test_ctx.initiator_static_public_key); + assert_eq!(initiator_completed_handshake_info.their_node_id, test_ctx.responder_static_public_key); - // The nodes should be able to communicate over the conduit. - do_conduit_tests(generator, &mut initiator_conduit, &mut responder_conduit, false) + // The nodes should be able to communicate with the Encryptor/Decryptors + do_encrypted_communication_tests(generator, &mut initiator_completed_handshake_info, &mut responder_completed_handshake_info, false) } // Either returns (act, false) or (random_bytes, true) where random_bytes is the same len as act @@ -238,7 +241,7 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr assert!(used_generated_data); return Ok(()); } - _ => panic!("responder required to output act bytes and no conduit/pubkey") + _ => panic!("responder required to output act bytes and no completed_handshake_info") }; } let act2 = act2_option.unwrap(); @@ -263,7 +266,7 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr act3_option = Some(act3); initiator_completed_handshake_info_option = Some(completed_handshake_info_option_inner); - // Valid conduit and pubkey indicates handshake is over + // Valid completed_handshake_info indicates handshake is over break; } // Partial act @@ -273,11 +276,11 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr assert!(used_generated_data); return Ok(()); } - _ => panic!("initiator required to output act bytes, conduit, and pubkey") + _ => panic!("initiator required to output act bytes and completed_handshake_info") }; } - // Ensure we actually received act3 bytes, conduit, and remote pubkey from process_act() + // Ensure we actually received act3 bytes, completed_handshake_info from process_act() let act3 = act3_option.unwrap(); let mut initiator_completed_handshake_info = initiator_completed_handshake_info_option.unwrap(); @@ -299,7 +302,7 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr Ok((None, Some(completed_handshake_info_inner))) => { responder_completed_handshake_info = Some(completed_handshake_info_inner); - // Valid conduit and pubkey indicates handshake is over + // Valid completed_handshake_info indicates handshake is over break; }, // partial act @@ -309,10 +312,10 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr assert!(used_generated_data); return Ok(()); }, - _ => panic!("responder required to output conduit, and pubkey") + _ => panic!("responder required to output completed_handshake_info") }; } - // Ensure we actually received conduit and remote pubkey from process_act() + // Ensure we actually received completed_handshake_info from process_act() let mut responder_completed_handshake_info = responder_completed_handshake_info.unwrap(); // The handshake should complete with each peer knowing the static_public_key of the remote peer @@ -325,8 +328,8 @@ fn do_handshake_test(generator: &mut FuzzGen) -> Result<(), GeneratorFinishedErr return Ok(()); } - // The nodes should be able to communicate over the conduit - do_conduit_tests(generator, &mut initiator_completed_handshake_info.conduit, &mut responder_completed_handshake_info.conduit, used_generated_data) + // The nodes should be able to communicate over the encryptor/decryptor + do_encrypted_communication_tests(generator, &mut initiator_completed_handshake_info, &mut responder_completed_handshake_info, used_generated_data) } #[inline] diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/conduit.rs index 602390eaff2..e92642e60a4 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/conduit.rs @@ -11,12 +11,37 @@ const TAGGED_MESSAGE_LENGTH_HEADER_SIZE: usize = MESSAGE_LENGTH_HEADER_SIZE + ch const KEY_ROTATION_INDEX: u32 = 1000; -/// Returned after a successful handshake to encrypt and decrypt communication with peer nodes. -/// It should not normally be manually instantiated. -/// Automatically handles key rotation. -pub struct Conduit { - pub encryptor: Encryptor, - pub decryptor: Decryptor, +/// Instantiate a new (Encryptor, Decryptor) with specified sending and receiving keys +pub fn create_encryptor_decryptor(sending_key: SymmetricKey, receiving_key: SymmetricKey, chaining_key: SymmetricKey) -> (Encryptor, Decryptor) { + (Encryptor { + sending_key, + sending_chaining_key: chaining_key, + sending_nonce: 0 + }, + Decryptor { + receiving_key, + receiving_chaining_key: chaining_key, + receiving_nonce: 0, + read_buffer: Some(vec![]), + pending_message_length: None, + decrypted_payloads: VecDeque::new(), + }) +} + +// Shared helper for the Encryptor and Decryptor +fn increment_nonce_helper(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { + *nonce += 1; + if *nonce == KEY_ROTATION_INDEX { + rotate_key(chaining_key, key); + *nonce = 0; + } +} + +// Shared helper for the Encryptor and Decryptor +fn rotate_key(chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { + let (new_chaining_key, new_key) = hkdf5869rfc::derive(chaining_key, key); + chaining_key.copy_from_slice(&new_chaining_key); + key.copy_from_slice(&new_key); } pub struct Encryptor { @@ -43,41 +68,6 @@ impl Iterator for Decryptor { } } -impl Conduit { - /// Instantiate a new Conduit with specified sending and receiving keys - pub fn new(sending_key: SymmetricKey, receiving_key: SymmetricKey, chaining_key: SymmetricKey) -> Self { - Conduit { - encryptor: Encryptor { - sending_key, - sending_chaining_key: chaining_key, - sending_nonce: 0 - }, - decryptor: Decryptor { - receiving_key, - receiving_chaining_key: chaining_key, - receiving_nonce: 0, - read_buffer: Some(vec![]), - pending_message_length: None, - decrypted_payloads: VecDeque::new(), - } - } - } - - fn increment_nonce(nonce: &mut u32, chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { - *nonce += 1; - if *nonce == KEY_ROTATION_INDEX { - Self::rotate_key(chaining_key, key); - *nonce = 0; - } - } - - fn rotate_key(chaining_key: &mut SymmetricKey, key: &mut SymmetricKey) { - let (new_chaining_key, new_key) = hkdf5869rfc::derive(chaining_key, key); - chaining_key.copy_from_slice(&new_chaining_key); - key.copy_from_slice(&new_key); - } -} - impl Encryptor { pub fn encrypt(&mut self, buffer: &[u8]) -> Vec { let length = buffer.len() as u16; @@ -95,7 +85,7 @@ impl Encryptor { } fn increment_nonce(&mut self) { - Conduit::increment_nonce(&mut self.sending_nonce, &mut self.sending_chaining_key, &mut self.sending_key); + increment_nonce_helper(&mut self.sending_nonce, &mut self.sending_chaining_key, &mut self.sending_key); } } @@ -177,7 +167,7 @@ impl Decryptor { } fn increment_nonce(&mut self) { - Conduit::increment_nonce(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); + increment_nonce_helper(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); } // Used in tests to determine whether or not excess bytes entered the conduit without needing to bring up @@ -193,11 +183,10 @@ impl Decryptor { #[cfg(test)] mod tests { + use super::*; use hex; - use ln::peers::conduit::Conduit; - - fn setup_peers() -> (Conduit, Conduit) { + fn setup_peers() -> ((Encryptor, Decryptor), (Encryptor, Decryptor)) { let chaining_key_vec = hex::decode("919219dbb2920afa8db80f9a51787a840bcf111ed8d588caf9ab4be716e42b01").unwrap(); let mut chaining_key = [0u8; 32]; chaining_key.copy_from_slice(&chaining_key_vec); @@ -210,22 +199,22 @@ mod tests { let mut receiving_key = [0u8; 32]; receiving_key.copy_from_slice(&receiving_key_vec); - let connected_peer = Conduit::new(sending_key, receiving_key, chaining_key); - let remote_peer = Conduit::new(receiving_key, sending_key, chaining_key); + let connected_peer = create_encryptor_decryptor(sending_key, receiving_key, chaining_key); + let remote_peer = create_encryptor_decryptor(receiving_key, sending_key, chaining_key); (connected_peer, remote_peer) } #[test] fn test_empty_message() { - let (mut connected_peer, mut remote_peer) = setup_peers(); + let ((mut connected_encryptor, _), (_, mut remote_decryptor)) = setup_peers(); let message: Vec = vec![]; - let encrypted_message = connected_peer.encryptor.encrypt(&message); + let encrypted_message = connected_encryptor.encrypt(&message); assert_eq!(encrypted_message.len(), 2 + 16 + 16); - remote_peer.decryptor.read(&encrypted_message[..]).unwrap(); - let decrypted_message = remote_peer.decryptor.next().unwrap(); + remote_decryptor.read(&encrypted_message[..]).unwrap(); + let decrypted_message = remote_decryptor.next().unwrap(); assert_eq!(decrypted_message, vec![]); } @@ -234,16 +223,16 @@ mod tests { // data is written to the read_buffer properly. #[test] fn test_decrypt_from_slice_two_calls_no_header_then_rest() { - let (mut connected_peer, mut remote_peer) = setup_peers(); + let ((mut connected_encryptor, _), (_, mut remote_decryptor)) = setup_peers(); let message: Vec = vec![1]; - let encrypted_message = connected_peer.encryptor.encrypt(&message); + let encrypted_message = connected_encryptor.encrypt(&message); - remote_peer.decryptor.read(&encrypted_message[..1]).unwrap(); - assert!(remote_peer.decryptor.next().is_none()); + remote_decryptor.read(&encrypted_message[..1]).unwrap(); + assert!(remote_decryptor.next().is_none()); - remote_peer.decryptor.read(&encrypted_message[1..]).unwrap(); - let decrypted_message = remote_peer.decryptor.next().unwrap(); + remote_decryptor.read(&encrypted_message[1..]).unwrap(); + let decrypted_message = remote_decryptor.next().unwrap(); assert_eq!(decrypted_message, vec![1]); } @@ -251,43 +240,43 @@ mod tests { // Include the header in the first slice #[test] fn test_decrypt_from_slice_two_calls_header_then_rest() { - let (mut connected_peer, mut remote_peer) = setup_peers(); + let ((mut connected_encryptor, _), (_, mut remote_decryptor)) = setup_peers(); let message: Vec = vec![1]; - let encrypted_message = connected_peer.encryptor.encrypt(&message); + let encrypted_message = connected_encryptor.encrypt(&message); - remote_peer.decryptor.read(&encrypted_message[..20]).unwrap(); - assert!(remote_peer.decryptor.next().is_none()); + remote_decryptor.read(&encrypted_message[..20]).unwrap(); + assert!(remote_decryptor.next().is_none()); - remote_peer.decryptor.read(&encrypted_message[20..]).unwrap(); - let decrypted_message = remote_peer.decryptor.next().unwrap(); + remote_decryptor.read(&encrypted_message[20..]).unwrap(); + let decrypted_message = remote_decryptor.next().unwrap(); assert_eq!(decrypted_message, vec![1]); } #[test] fn test_nonce_chaining() { - let (mut connected_peer, _remote_peer) = setup_peers(); + let ((mut connected_encryptor, _), _) = setup_peers(); let message = hex::decode("68656c6c6f").unwrap(); - let encrypted_message = connected_peer.encryptor.encrypt(&message); + let encrypted_message = connected_encryptor.encrypt(&message); assert_eq!(encrypted_message, hex::decode("cf2b30ddf0cf3f80e7c35a6e6730b59fe802473180f396d88a8fb0db8cbcf25d2f214cf9ea1d95").unwrap()); // the second time the same message is encrypted, the ciphertext should be different - let encrypted_message = connected_peer.encryptor.encrypt(&message); + let encrypted_message = connected_encryptor.encrypt(&message); assert_eq!(encrypted_message, hex::decode("72887022101f0b6753e0c7de21657d35a4cb2a1f5cde2650528bbc8f837d0f0d7ad833b1a256a1").unwrap()); } #[test] /// Based on RFC test vectors: https://github.com/lightningnetwork/lightning-rfc/blob/master/08-transport.md#message-encryption-tests fn test_key_rotation() { - let (mut connected_peer, _remote_peer) = setup_peers(); + let ((mut connected_encryptor, _), _) = setup_peers(); let message = hex::decode("68656c6c6f").unwrap(); let mut encrypted_messages: Vec> = Vec::new(); for _ in 0..1002 { - let encrypted_message = connected_peer.encryptor.encrypt(&message); + let encrypted_message = connected_encryptor.encrypt(&message); encrypted_messages.push(encrypted_message); } @@ -299,13 +288,13 @@ mod tests { #[test] fn test_decryption_buffering() { - let (mut connected_peer, mut remote_peer) = setup_peers(); + let ((mut connected_encryptor, _), (_, mut remote_decryptor)) = setup_peers(); let message = hex::decode("68656c6c6f").unwrap(); let mut encrypted_messages: Vec> = Vec::new(); for _ in 0..1002 { - let encrypted_message = connected_peer.encryptor.encrypt(&message); + let encrypted_message = connected_encryptor.encrypt(&message); encrypted_messages.push(encrypted_message); } @@ -314,16 +303,16 @@ mod tests { let mut current_encrypted_message = encrypted_messages.remove(0); let next_encrypted_message = encrypted_messages.remove(0); current_encrypted_message.extend_from_slice(&next_encrypted_message); - remote_peer.decryptor.read(¤t_encrypted_message[..]).unwrap(); + remote_decryptor.read(¤t_encrypted_message[..]).unwrap(); - let decrypted_message = remote_peer.decryptor.next().unwrap(); + let decrypted_message = remote_decryptor.next().unwrap(); assert_eq!(decrypted_message, message); } for _ in 0..501 { // decrypt messages directly from buffer without adding to it - remote_peer.decryptor.read(&[]).unwrap(); - let decrypted_message = remote_peer.decryptor.next().unwrap(); + remote_decryptor.read(&[]).unwrap(); + let decrypted_message = remote_decryptor.next().unwrap(); assert_eq!(decrypted_message, message); } } @@ -331,29 +320,29 @@ mod tests { // Decryption errors should result in Err #[test] fn decryption_failure_errors() { - let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encryptor.encrypt(&[1]); + let ((mut connected_encryptor, _), (_, mut remote_decryptor)) = setup_peers(); + let encrypted = connected_encryptor.encrypt(&[1]); - connected_peer.decryptor.receiving_key = [0; 32]; - assert_eq!(connected_peer.decryptor.read(&encrypted), Err("invalid hmac".to_string())); + remote_decryptor.receiving_key = [0; 32]; + assert_eq!(remote_decryptor.read(&encrypted), Err("invalid hmac".to_string())); } // Test next()::None #[test] fn decryptor_iterator_empty() { - let (mut connected_peer, _) = setup_peers(); + let (_, (_, mut remote_decryptor)) = setup_peers(); - assert_eq!(connected_peer.decryptor.next(), None); + assert_eq!(remote_decryptor.next(), None); } // Test next() -> next()::None #[test] fn decryptor_iterator_one_item_valid() { - let (mut connected_peer, mut remote_peer) = setup_peers(); - let encrypted = remote_peer.encryptor.encrypt(&[1]); - connected_peer.decryptor.read(&encrypted).unwrap(); + let ((mut connected_encryptor, _), (_, mut remote_decryptor)) = setup_peers(); + let encrypted = connected_encryptor.encrypt(&[1]); + remote_decryptor.read(&encrypted).unwrap(); - assert_eq!(connected_peer.decryptor.next(), Some(vec![1])); - assert_eq!(connected_peer.decryptor.next(), None); + assert_eq!(remote_decryptor.next(), Some(vec![1])); + assert_eq!(remote_decryptor.next(), None); } } \ No newline at end of file diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 4f9ee039b60..68f963bdead 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -1,10 +1,10 @@ //! Execute handshakes for peer-to-peer connection establishment. //! Handshake states can be advanced automatically, or by manually calling the appropriate step. -//! Once complete, returns an instance of Conduit. +//! Once complete, returns an instance of CompletedHandshakeInfo. use bitcoin::secp256k1::{PublicKey, SecretKey}; -use ln::peers::conduit::Conduit; +use ln::peers::conduit::{Decryptor, Encryptor}; use ln::peers::handshake::acts::Act; use ln::peers::handshake::states::HandshakeState; use ln::peers::transport::IPeerHandshake; @@ -29,7 +29,8 @@ pub struct PeerHandshake { /// Container for the information returned from a successfully completed handshake pub struct CompletedHandshakeInfo { - pub conduit: Conduit, + pub decryptor: Decryptor, + pub encryptor: Encryptor, pub their_node_id: PublicKey, } diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index c038fc7ed8f..8ec0e651fa8 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -5,7 +5,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::{chacha, hkdf5869rfc}; -use ln::peers::conduit::{Conduit, SymmetricKey}; +use ln::peers::conduit::{SymmetricKey, create_encryptor_decryptor}; use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; use ln::peers::handshake::{CompletedHandshakeInfo, IHandshakeState}; @@ -303,8 +303,8 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { let (sending_key, receiving_key) = hkdf5869rfc::derive(&chaining_key, &[0; 0]); // 7. rn = 0, sn = 0 - // - done by Conduit - let conduit = Conduit::new(sending_key, receiving_key, chaining_key); + // - done by encryptor/decryptor initialization + let (encryptor, decryptor) = create_encryptor_decryptor(sending_key, receiving_key, chaining_key); // 8. Send m = 0 || c || t act_three[0] = 0; @@ -312,7 +312,8 @@ impl IHandshakeState for InitiatorAwaitingActTwoState { Some(Act::Three(act_three)), HandshakeState::Complete(Some( CompletedHandshakeInfo { - conduit, + decryptor, + encryptor, their_node_id: responder_static_public_key } )) @@ -386,18 +387,19 @@ impl IHandshakeState for ResponderAwaitingActThreeState { let (receiving_key, sending_key) = hkdf5869rfc::derive(&chaining_key, &[0; 0]); // 10. rn = 0, sn = 0 - // - done by Conduit - let mut conduit = Conduit::new(sending_key, receiving_key, chaining_key); + // - done by encryptor/decryptor initialization + let (encryptor, mut decryptor) = create_encryptor_decryptor(sending_key, receiving_key, chaining_key); // Any remaining data in the read buffer would be encrypted, so transfer ownership - // to the Conduit for future use. - conduit.decryptor.read(&input[bytes_read..])?; + // to the Decryptor for future use. + decryptor.read(&input[bytes_read..])?; Ok(( None, HandshakeState::Complete(Some( CompletedHandshakeInfo { - conduit, + decryptor, + encryptor, their_node_id: initiator_pubkey } )) @@ -699,7 +701,7 @@ mod test { assert_eq!(act3.as_ref(), test_ctx.valid_act3.as_slice()); assert_eq!(completed_handshake_info.their_node_id, test_ctx.responder_static_public_key); - assert_eq!(0, completed_handshake_info.conduit.decryptor.read_buffer_length()); + assert_eq!(0, completed_handshake_info.decryptor.read_buffer_length()); } // Initiator::AwaitingActTwo -> Complete (segmented calls) @@ -765,7 +767,7 @@ mod test { }; assert_eq!(completed_handshake_info.their_node_id, test_ctx.initiator_public_key); - assert_eq!(0, completed_handshake_info.conduit.decryptor.read_buffer_length()); + assert_eq!(0, completed_handshake_info.decryptor.read_buffer_length()); } // Responder::AwaitingActThree -> None (with extra bytes) @@ -785,7 +787,7 @@ mod test { }; assert_eq!(completed_handshake_info.their_node_id, test_ctx.initiator_public_key); - assert_eq!(16, completed_handshake_info.conduit.decryptor.read_buffer_length()); + assert_eq!(16, completed_handshake_info.decryptor.read_buffer_length()); } // Responder::AwaitingActThree -> Error (bad version bytes) diff --git a/lightning/src/ln/peers/test_util.rs b/lightning/src/ln/peers/test_util.rs index 539f83265d6..9ed4d72cbb9 100644 --- a/lightning/src/ln/peers/test_util.rs +++ b/lightning/src/ln/peers/test_util.rs @@ -3,7 +3,7 @@ use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; -use ln::peers::conduit::Conduit; +use ln::peers::conduit; use ln::peers::handler::{SocketDescriptor, ITransport, PeerHandleError, MessageQueuer}; use ln::peers::handshake::CompletedHandshakeInfo; use ln::peers::transport::{IPeerHandshake, PayloadQueuer}; @@ -94,11 +94,12 @@ impl IPeerHandshake for PeerHandshakeTestStubComplete { let curve = secp256k1::Secp256k1::new(); let private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); let public_key = PublicKey::from_secret_key(&curve, &private_key); - let conduit = Conduit::new([0;32], [0;32], [0;32]); + let (encryptor, decryptor) = conduit::create_encryptor_decryptor([0;32], [0;32], [0;32]); Ok((None, Some( CompletedHandshakeInfo { - conduit, + decryptor, + encryptor, their_node_id: public_key } ))) diff --git a/lightning/src/ln/peers/transport.rs b/lightning/src/ln/peers/transport.rs index a750fb7237e..8cca07d1b93 100644 --- a/lightning/src/ln/peers/transport.rs +++ b/lightning/src/ln/peers/transport.rs @@ -2,7 +2,6 @@ use bitcoin::secp256k1::{SecretKey, PublicKey}; -use ln::peers::conduit::Conduit; use ln::peers::handler::{ITransport, PeerHandleError, MessageQueuer}; use ln::peers::handshake::{CompletedHandshakeInfo, PeerHandshake}; use ln::{wire, msgs}; @@ -23,7 +22,7 @@ pub trait IPeerHandshake { /// Instantiate a new inbound handshake fn new_inbound(responder_static_private_key: &SecretKey, responder_ephemeral_private_key: &SecretKey) -> Self; - /// Progress the handshake given bytes received from the peer. Returns Some(Conduit, PublicKey) when the handshake + /// Progress the handshake given bytes received from the peer. Returns Some(CompletedHandshakeInfo) when the handshake /// is complete. fn process_act(&mut self, input: &[u8]) -> Result<(Option>, Option), String>; } @@ -41,17 +40,15 @@ pub(super) trait PayloadQueuer { } pub(super) struct Transport { - pub(super) conduit: Option, handshake: PeerHandshakeImpl, - their_node_id: Option, + completed_handshake_info: Option } impl ITransport for Transport { fn new_outbound(initiator_static_private_key: &SecretKey, responder_static_public_key: &PublicKey, initiator_ephemeral_private_key: &SecretKey) -> Self { Self { - conduit: None, + completed_handshake_info: None, handshake: PeerHandshakeImpl::new_outbound(initiator_static_private_key, responder_static_public_key, initiator_ephemeral_private_key), - their_node_id: None, } } @@ -61,14 +58,13 @@ impl ITransport for Transport Self { Self { - conduit: None, + completed_handshake_info: None, handshake: PeerHandshakeImpl::new_inbound(responder_static_private_key, responder_ephemeral_private_key), - their_node_id: None, } } fn process_input(&mut self, input: &[u8], output_buffer: &mut impl PayloadQueuer) -> Result { - match self.conduit { + match self.completed_handshake_info { // Continue handshake None => { let (response_option, completed_handshake_info_option) = self.handshake.process_act(input)?; @@ -80,15 +76,14 @@ impl ITransport for Transport { - conduit.decryptor.read(input)?; + Some(ref mut completed_handshake_info) => { + completed_handshake_info.decryptor.read(input)?; Ok(false) // newly connected } } @@ -99,10 +94,10 @@ impl ITransport for Transport {} - Some(ref mut conduit) => { - for msg_data in &mut conduit.decryptor { + Some(ref mut completed_handshake_info) => { + for msg_data in &mut completed_handshake_info.decryptor { let mut reader = ::std::io::Cursor::new(&msg_data[..]); let message_result = wire::read(&mut reader); let message = match message_result { @@ -137,12 +132,12 @@ impl ITransport for Transport bool { - self.conduit.is_some() + self.completed_handshake_info.is_some() } fn get_their_node_id(&self) -> PublicKey { assert!(self.is_connected(), "Retrieving the remote node_id is only supported after transport is connected"); - self.their_node_id.unwrap() + self.completed_handshake_info.as_ref().unwrap().their_node_id } } @@ -150,14 +145,14 @@ impl MessageQueuer for Transport(&mut self, message: &M, output_buffer: &mut Q, logger: L) where L::Target: Logger { - match self.conduit { + match self.completed_handshake_info { None => panic!("Enqueueing messages only supported after transport is connected"), - Some(ref mut conduit) => { - log_trace!(logger, "Enqueueing message of type {} to {}", message.type_id(), log_pubkey!(self.their_node_id.unwrap())); + Some(ref mut completed_handshake_info) => { + log_trace!(logger, "Enqueueing message of type {} to {}", message.type_id(), log_pubkey!(completed_handshake_info.their_node_id)); let mut buffer = VecWriter(Vec::new()); wire::write(message, &mut buffer).unwrap(); - output_buffer.push_back(conduit.encryptor.encrypt(&buffer.0)); + output_buffer.push_back(completed_handshake_info.encryptor.encrypt(&buffer.0)); } } } From 717321536c1814fbf2ac166219b755711f7351a4 Mon Sep 17 00:00:00 2001 From: Julian Knutsen Date: Wed, 9 Sep 2020 09:48:34 -0700 Subject: [PATCH 96/96] refactor: Rename conduit.rs and clean up remaining references Clean up the loose comments, test names, and variables names that still referred to conduit now that it has been destructured. --- fuzz/src/peer_crypt.rs | 4 ++-- lightning/src/ln/peers/{conduit.rs => encryption.rs} | 4 ++-- lightning/src/ln/peers/handshake/mod.rs | 6 +++--- lightning/src/ln/peers/handshake/states.rs | 6 +++--- lightning/src/ln/peers/mod.rs | 9 +++++---- lightning/src/ln/peers/test_util.rs | 6 +++--- 6 files changed, 18 insertions(+), 17 deletions(-) rename lightning/src/ln/peers/{conduit.rs => encryption.rs} (99%) diff --git a/fuzz/src/peer_crypt.rs b/fuzz/src/peer_crypt.rs index c65c381a432..c7f538e23b7 100644 --- a/fuzz/src/peer_crypt.rs +++ b/fuzz/src/peer_crypt.rs @@ -101,8 +101,8 @@ impl TestCtx { } } -// Common test function that sends encrypted messages between an encryptor/decryptor until the source -// data runs out. +// Common test function that sends encrypted messages between an encryptor/decryptor until the +// source data runs out. #[inline] fn do_encrypted_communication_tests(generator: &mut FuzzGen, initiator_completed_handshake_info: &mut CompletedHandshakeInfo, diff --git a/lightning/src/ln/peers/conduit.rs b/lightning/src/ln/peers/encryption.rs similarity index 99% rename from lightning/src/ln/peers/conduit.rs rename to lightning/src/ln/peers/encryption.rs index e92642e60a4..2d7265f7540 100644 --- a/lightning/src/ln/peers/conduit.rs +++ b/lightning/src/ln/peers/encryption.rs @@ -170,8 +170,8 @@ impl Decryptor { increment_nonce_helper(&mut self.receiving_nonce, &mut self.receiving_chaining_key, &mut self.receiving_key); } - // Used in tests to determine whether or not excess bytes entered the conduit without needing to bring up - // infrastructure to properly encode it + // Used in tests to determine whether or not excess bytes entered the Decryptor without needing + // to bring up infrastructure to properly encode it #[cfg(test)] pub fn read_buffer_length(&self) -> usize { match &self.read_buffer { diff --git a/lightning/src/ln/peers/handshake/mod.rs b/lightning/src/ln/peers/handshake/mod.rs index 68f963bdead..7ca4253b813 100644 --- a/lightning/src/ln/peers/handshake/mod.rs +++ b/lightning/src/ln/peers/handshake/mod.rs @@ -4,7 +4,7 @@ use bitcoin::secp256k1::{PublicKey, SecretKey}; -use ln::peers::conduit::{Decryptor, Encryptor}; +use ln::peers::encryption::{Decryptor, Encryptor}; use ln::peers::handshake::acts::Act; use ln::peers::handshake::states::HandshakeState; use ln::peers::transport::IPeerHandshake; @@ -52,8 +52,8 @@ impl IPeerHandshake for PeerHandshake { self.ready_to_process = true; // This transition does not have a failure path - let (response_vec_option, conduit_and_remote_static_public_key_option) = self.process_act(&[]).unwrap(); - assert!(conduit_and_remote_static_public_key_option.is_none()); + let (response_vec_option, completed_handshake_info) = self.process_act(&[]).unwrap(); + assert!(completed_handshake_info.is_none()); response_vec_option.unwrap() } diff --git a/lightning/src/ln/peers/handshake/states.rs b/lightning/src/ln/peers/handshake/states.rs index 8ec0e651fa8..e4785f73820 100644 --- a/lightning/src/ln/peers/handshake/states.rs +++ b/lightning/src/ln/peers/handshake/states.rs @@ -5,7 +5,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{SecretKey, PublicKey}; use ln::peers::{chacha, hkdf5869rfc}; -use ln::peers::conduit::{SymmetricKey, create_encryptor_decryptor}; +use ln::peers::encryption::{SymmetricKey, create_encryptor_decryptor}; use ln::peers::handshake::acts::{Act, ActBuilder, ACT_ONE_LENGTH, ACT_TWO_LENGTH, ACT_THREE_LENGTH, EMPTY_ACT_ONE, EMPTY_ACT_TWO, EMPTY_ACT_THREE}; use ln::peers::handshake::{CompletedHandshakeInfo, IHandshakeState}; @@ -771,10 +771,10 @@ mod test { } // Responder::AwaitingActThree -> None (with extra bytes) - // Ensures that any remaining data in the read buffer is transferred to the conduit once + // Ensures that any remaining data in the read buffer is transferred to the Decryptor once // the handshake is complete #[test] - fn awaiting_act_three_excess_bytes_after_complete_are_in_conduit() { + fn awaiting_act_three_excess_bytes_after_complete_are_in_decryptor() { let test_ctx = TestCtx::new(); let (_act2, awaiting_act_three_state) = do_next_or_panic!(test_ctx.responder, &test_ctx.valid_act1); let mut act3 = test_ctx.valid_act3; diff --git a/lightning/src/ln/peers/mod.rs b/lightning/src/ln/peers/mod.rs index 5e8efb77d87..dec07d31c5d 100644 --- a/lightning/src/ln/peers/mod.rs +++ b/lightning/src/ln/peers/mod.rs @@ -1,7 +1,8 @@ //! Everything that has to do with over-the-wire peer communication. //! The handshake module exposes mechanisms to conduct inbound and outbound handshakes. -//! When a handshake completes, it returns an instance of Conduit. -//! Conduit enables message encryption and decryption, and automatically handles key rotation. +//! When a handshake completes, it returns an instance of CompletedPeerHandshake containing an +//! Encryptor/Decryptor used for encrypted communication and the remote static public key used for +//! identification. #[cfg(test)] #[macro_use] @@ -17,9 +18,9 @@ mod hkdf5869rfc; mod outbound_queue; #[cfg(feature = "fuzztarget")] -pub mod conduit; +pub mod encryption; #[cfg(not(feature = "fuzztarget"))] -mod conduit; +mod encryption; #[cfg(feature = "fuzztarget")] pub mod handshake; diff --git a/lightning/src/ln/peers/test_util.rs b/lightning/src/ln/peers/test_util.rs index 9ed4d72cbb9..1d847cfd479 100644 --- a/lightning/src/ln/peers/test_util.rs +++ b/lightning/src/ln/peers/test_util.rs @@ -3,7 +3,7 @@ use bitcoin::secp256k1; use bitcoin::secp256k1::key::{PublicKey, SecretKey}; -use ln::peers::conduit; +use ln::peers::encryption::{create_encryptor_decryptor}; use ln::peers::handler::{SocketDescriptor, ITransport, PeerHandleError, MessageQueuer}; use ln::peers::handshake::CompletedHandshakeInfo; use ln::peers::transport::{IPeerHandshake, PayloadQueuer}; @@ -74,7 +74,7 @@ impl IPeerHandshake for PeerHandshakeTestStubBytes { } } -/// Stub implementation of IPeerhandshake that returns Some(Conduit, PublicKey) +/// Stub implementation of IPeerhandshake that returns Some(CompletedHandshakeInfo) pub(super) struct PeerHandshakeTestStubComplete { } impl IPeerHandshake for PeerHandshakeTestStubComplete { @@ -94,7 +94,7 @@ impl IPeerHandshake for PeerHandshakeTestStubComplete { let curve = secp256k1::Secp256k1::new(); let private_key = SecretKey::from_slice(&[0x_21_u8; 32]).unwrap(); let public_key = PublicKey::from_secret_key(&curve, &private_key); - let (encryptor, decryptor) = conduit::create_encryptor_decryptor([0;32], [0;32], [0;32]); + let (encryptor, decryptor) = create_encryptor_decryptor([0;32], [0;32], [0;32]); Ok((None, Some( CompletedHandshakeInfo {