Add SendError enum for onion messages and error on too-big packets
authorValentine Wallace <vwallace@protonmail.com>
Thu, 23 Jun 2022 19:47:25 +0000 (15:47 -0400)
committerValentine Wallace <vwallace@protonmail.com>
Tue, 2 Aug 2022 23:19:39 +0000 (19:19 -0400)
lightning/src/onion_message/functional_tests.rs
lightning/src/onion_message/messenger.rs
lightning/src/onion_message/mod.rs

index 510852cef837860c7db7dd89600e0e5afdcc8f51..560028c5bbaaf86228b2ded9a2d4e7bec70686b1 100644 (file)
 //! 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;
 
@@ -105,3 +105,17 @@ fn three_blinded_hops() {
        nodes[0].messenger.send_onion_message(&[], Destination::BlindedRoute(blinded_route)).unwrap();
        pass_along_path(nodes, 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 = [hop_node_id; 400];
+       let err = nodes[0].messenger.send_onion_message(&hops, Destination::Node(hop_node_id)).unwrap_err();
+       assert_eq!(err, SendError::TooBigPacket);
+}
index 930d90ebac37c2936f0be0de0bf1eb0556a64362..6f5d9e8a52cfbab42b5818540dc686398dabb20d 100644 (file)
@@ -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<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
        where K::Target: KeysInterface<Signer = Signer>,
              L::Target: Logger,
@@ -127,7 +139,7 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
 
        /// Send an empty onion message to `destination`, routing it through `intermediate_nodes`.
        /// See [`OnionMessenger`] for example usage.
-       pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], destination: Destination) -> Result<(), secp256k1::Error> {
+       pub fn send_onion_message(&self, intermediate_nodes: &[PublicKey], 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 {
@@ -140,10 +152,12 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
                        }
                };
                let (packet_payloads, packet_keys) = packet_payloads_and_keys(
-                       &self.secp_ctx, intermediate_nodes, destination, &blinding_secret)?;
+                       &self.secp_ctx, intermediate_nodes, destination, &blinding_secret)
+                       .map_err(|e| SendError::Secp256k1(e))?;
 
                let prng_seed = self.keys_manager.get_secure_random_bytes();
-               let onion_packet = construct_onion_message_packet(packet_payloads, packet_keys, prng_seed);
+               let onion_packet = construct_onion_message_packet(
+                       packet_payloads, 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());
@@ -343,7 +357,8 @@ fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
        Ok((payloads, onion_packet_keys))
 }
 
-fn construct_onion_message_packet(payloads: Vec<(Payload, [u8; 32])>, onion_keys: Vec<onion_utils::OnionKeys>, prng_seed: [u8; 32]) -> Packet {
+/// 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<onion_utils::OnionKeys>, prng_seed: [u8; 32]) -> Result<Packet, ()> {
        // Spec rationale:
        // "`len` allows larger messages to be sent than the standard 1300 bytes allowed for an HTLC
        // onion, but this should be used sparingly as it is reduces anonymity set, hence the
@@ -353,7 +368,8 @@ fn construct_onion_message_packet(payloads: Vec<(Payload, [u8; 32])>, onion_keys
                SMALL_PACKET_HOP_DATA_LEN
        } else if payloads_ser_len <= BIG_PACKET_HOP_DATA_LEN {
                BIG_PACKET_HOP_DATA_LEN
-       } else { payloads_ser_len };
+       } else { return Err(()) };
 
-       onion_utils::construct_onion_message_packet::<_, _>(payloads, onion_keys, prng_seed, hop_data_len)
+       Ok(onion_utils::construct_onion_message_packet::<_, _>(
+               payloads, onion_keys, prng_seed, hop_data_len))
 }
index 966b10b60fbd6be7d6d3ebac6166bddf7bd92e23..2e23b76ada33ac8f1a7355943edb8d5c9ee25392 100644 (file)
@@ -29,5 +29,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;