From 059e39ccf293713e8a758bbd1c887c3f80c301b5 Mon Sep 17 00:00:00 2001 From: Valentine Wallace Date: Thu, 23 Jun 2022 15:47:25 -0400 Subject: [PATCH] Add SendError enum for onion messages and error on too-big packets --- .../src/onion_message/functional_tests.rs | 18 +++++++++-- lightning/src/onion_message/messenger.rs | 31 ++++++++++++++----- lightning/src/onion_message/mod.rs | 2 +- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/lightning/src/onion_message/functional_tests.rs b/lightning/src/onion_message/functional_tests.rs index 46751fef441..c20491b3665 100644 --- a/lightning/src/onion_message/functional_tests.rs +++ b/lightning/src/onion_message/functional_tests.rs @@ -10,12 +10,12 @@ //! Onion message testing and test utilities live here. use chain::keysinterface::{KeysInterface, Recipient}; -use super::{BlindedRoute, Destination, OnionMessenger}; +use super::{BlindedRoute, Destination, OnionMessenger, SendError}; use util::enforcing_trait_impls::EnforcingSigner; use util::test_utils; use bitcoin::network::constants::Network; -use bitcoin::secp256k1::{PublicKey, Secp256k1}; +use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; use sync::Arc; @@ -109,3 +109,17 @@ fn three_blinded_hops() { node1.messenger.send_onion_message(vec![], Destination::BlindedRoute(blinded_route)).unwrap(); pass_along_path(vec![&node1, &node2, &node3, &node4], None); } + +#[test] +fn too_big_packet_error() { + // Make sure we error as expected if a packet is too big to send. + let nodes = create_nodes(1); + + let hop_secret = SecretKey::from_slice(&hex::decode("0101010101010101010101010101010101010101010101010101010101010101").unwrap()[..]).unwrap(); + let secp_ctx = Secp256k1::new(); + let hop_node_id = PublicKey::from_secret_key(&secp_ctx, &hop_secret); + + let hops = vec![hop_node_id.clone(); 400]; + let err = nodes[0].messenger.send_onion_message(hops, Destination::Node(hop_node_id)).unwrap_err(); + assert_eq!(err, SendError::TooBigPacket); +} diff --git a/lightning/src/onion_message/messenger.rs b/lightning/src/onion_message/messenger.rs index cfef6f3f7d5..62d2677bd58 100644 --- a/lightning/src/onion_message/messenger.rs +++ b/lightning/src/onion_message/messenger.rs @@ -108,6 +108,18 @@ impl Destination { } } +/// Errors that may occur when [sending an onion message]. +/// +/// [sending an onion message]: OnionMessenger::send_onion_message +#[derive(Debug, PartialEq)] +pub enum SendError { + /// Errored computing onion message packet keys. + Secp256k1(secp256k1::Error), + /// Because implementations such as Eclair will drop onion messages where the message packet + /// exceeds 32834 bytes, we refuse to send messages where the packet exceeds this size. + TooBigPacket, +} + impl OnionMessenger where K::Target: KeysInterface, L::Target: Logger, @@ -126,7 +138,7 @@ impl OnionMessenger } /// Send an empty onion message to `destination`, routing it through `intermediate_nodes`. - pub fn send_onion_message(&self, intermediate_nodes: Vec, destination: Destination) -> Result<(), secp256k1::Error> { + pub fn send_onion_message(&self, intermediate_nodes: Vec, destination: Destination) -> Result<(), SendError> { let blinding_secret_bytes = self.keys_manager.get_secure_random_bytes(); let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted"); let (introduction_node_id, blinding_point) = if intermediate_nodes.len() != 0 { @@ -139,11 +151,13 @@ impl OnionMessenger } }; let (control_tlvs_keys, onion_packet_keys) = construct_sending_keys( - &self.secp_ctx, &intermediate_nodes, &destination, &blinding_secret)?; + &self.secp_ctx, &intermediate_nodes, &destination, &blinding_secret) + .map_err(|e| SendError::Secp256k1(e))?; let payloads = build_payloads(intermediate_nodes, destination, control_tlvs_keys); let prng_seed = self.keys_manager.get_secure_random_bytes(); - let onion_packet = construct_onion_message_packet(payloads, onion_packet_keys, prng_seed); + let onion_packet = construct_onion_message_packet( + payloads, onion_packet_keys, prng_seed).map_err(|()| SendError::TooBigPacket)?; let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap(); let pending_msgs = pending_per_peer_msgs.entry(introduction_node_id).or_insert(Vec::new()); @@ -359,19 +373,20 @@ fn build_payloads(intermediate_nodes: Vec, destination: Destination, payloads } -fn construct_onion_message_packet(payloads: Vec<(Payload, [u8; 32])>, onion_keys: Vec, prng_seed: [u8; 32]) -> Packet { - let payloads_serialized_len = payloads.iter().map(|p| p.serialized_length() + 32 /* HMAC */).sum(); +/// Errors if the serialized payload size exceeds onion_message::BIG_PACKET_HOP_DATA_LEN +fn construct_onion_message_packet(payloads: Vec<(Payload, [u8; 32])>, onion_keys: Vec, prng_seed: [u8; 32]) -> Result { + let payloads_serialized_len: usize = payloads.iter().map(|p| p.serialized_length() + 32 /* HMAC */).sum(); let hop_data_len = if payloads_serialized_len <= SMALL_PACKET_HOP_DATA_LEN { SMALL_PACKET_HOP_DATA_LEN } else if payloads_serialized_len <= BIG_PACKET_HOP_DATA_LEN { BIG_PACKET_HOP_DATA_LEN - } else { payloads_serialized_len }; + } else { return Err(()) }; let mut packet_data = vec![0; hop_data_len]; let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]); chacha.process_in_place(&mut packet_data); - onion_utils::construct_onion_packet_with_init_noise::<_, _>( - payloads, onion_keys, packet_data, None) + Ok(onion_utils::construct_onion_packet_with_init_noise::<_, _>( + payloads, onion_keys, packet_data, None)) } \ No newline at end of file diff --git a/lightning/src/onion_message/mod.rs b/lightning/src/onion_message/mod.rs index 1197af86e5c..e0567904890 100644 --- a/lightning/src/onion_message/mod.rs +++ b/lightning/src/onion_message/mod.rs @@ -30,5 +30,5 @@ mod functional_tests; // Re-export structs so they can be imported with just the `onion_message::` module prefix. pub use self::blinded_route::{BlindedRoute, BlindedHop}; -pub use self::messenger::{Destination, OnionMessenger, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; +pub use self::messenger::{Destination, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger}; pub(crate) use self::packet::Packet;