Skip to content

Commit

Permalink
Add SendError enum for onion messages and error on too-big packets
Browse files Browse the repository at this point in the history
  • Loading branch information
valentinewallace committed Jul 7, 2022
1 parent 0078878 commit 059e39c
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 11 deletions.
18 changes: 16 additions & 2 deletions lightning/src/onion_message/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
31 changes: 23 additions & 8 deletions lightning/src/onion_message/messenger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -126,7 +138,7 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
}

/// Send an empty onion message to `destination`, routing it through `intermediate_nodes`.
pub fn send_onion_message(&self, intermediate_nodes: Vec<PublicKey>, destination: Destination) -> Result<(), secp256k1::Error> {
pub fn send_onion_message(&self, intermediate_nodes: Vec<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 {
Expand All @@ -139,11 +151,13 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessenger<Signer, K, L>
}
};
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());
Expand Down Expand Up @@ -359,19 +373,20 @@ fn build_payloads(intermediate_nodes: Vec<PublicKey>, destination: Destination,
payloads
}

fn construct_onion_message_packet(payloads: Vec<(Payload, [u8; 32])>, onion_keys: Vec<onion_utils::OnionKeys>, 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<onion_utils::OnionKeys>, prng_seed: [u8; 32]) -> Result<Packet, ()> {
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))
}
2 changes: 1 addition & 1 deletion lightning/src/onion_message/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

0 comments on commit 059e39c

Please sign in to comment.