From 8f3750304b0e8f53fcf0d32915d289e7453a40a1 Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Thu, 26 Dec 2019 13:45:44 -0500 Subject: [PATCH] Move BogusHopData generation into test instead of OnionHopData. This, as it should be, restricts OnionHopData to only being able to represent valid states, while still allowing for tests to generate bogus hop data fields to test deserialization. --- lightning/src/ln/functional_tests.rs | 38 +++++++++++++++++++++++----- lightning/src/ln/msgs.rs | 7 ----- lightning/src/ln/onion_utils.rs | 14 +++++++++- 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs index b9a2dde8..936e785f 100644 --- a/lightning/src/ln/functional_tests.rs +++ b/lightning/src/ln/functional_tests.rs @@ -18,7 +18,7 @@ use util::enforcing_trait_impls::EnforcingChannelKeys; use util::test_utils; use util::events::{Event, EventsProvider, MessageSendEvent, MessageSendEventsProvider}; use util::errors::APIError; -use util::ser::{Writeable, ReadableArgs}; +use util::ser::{Writeable, Writer, ReadableArgs}; use util::config::UserConfig; use util::logger::Logger; @@ -44,7 +44,7 @@ use std::collections::{BTreeSet, HashMap, HashSet}; use std::default::Default; use std::sync::{Arc, Mutex}; use std::sync::atomic::Ordering; -use std::mem; +use std::{mem, io}; use rand::{thread_rng, Rng}; @@ -5007,6 +5007,20 @@ impl msgs::ChannelUpdate { } } +struct BogusOnionHopData { + data: Vec +} +impl BogusOnionHopData { + fn new(orig: msgs::OnionHopData) -> Self { + Self { data: orig.encode() } + } +} +impl Writeable for BogusOnionHopData { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + writer.write_all(&self.data[..]) + } +} + #[test] fn test_onion_failure() { use ln::msgs::ChannelUpdate; @@ -5036,8 +5050,14 @@ fn test_onion_failure() { let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1; let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap(); let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route, cur_height).unwrap(); - onion_payloads[0].format = msgs::OnionHopDataFormat::BogusRealm(3); - msg.onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash); + let mut new_payloads = Vec::new(); + for payload in onion_payloads.drain(..) { + new_payloads.push(BogusOnionHopData::new(payload)); + } + // break the first (non-final) hop payload by swapping the realm (0) byte for a byte + // describing a length-1 TLV payload, which is obviously bogus. + new_payloads[0].data[0] = 1; + msg.onion_routing_packet = onion_utils::construct_onion_packet_bogus_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash); }, ||{}, true, Some(PERM|1), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true}));//XXX incremented channels idx here // final node failure @@ -5046,8 +5066,14 @@ fn test_onion_failure() { let cur_height = nodes[0].node.latest_block_height.load(Ordering::Acquire) as u32 + 1; let onion_keys = onion_utils::construct_onion_keys(&Secp256k1::new(), &route, &session_priv).unwrap(); let (mut onion_payloads, _htlc_msat, _htlc_cltv) = onion_utils::build_onion_payloads(&route, cur_height).unwrap(); - onion_payloads[1].format = msgs::OnionHopDataFormat::BogusRealm(3); - msg.onion_routing_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, [0; 32], &payment_hash); + let mut new_payloads = Vec::new(); + for payload in onion_payloads.drain(..) { + new_payloads.push(BogusOnionHopData::new(payload)); + } + // break the last-hop payload by swapping the realm (0) byte for a byte describing a + // length-1 TLV payload, which is obviously bogus. + new_payloads[1].data[0] = 1; + msg.onion_routing_packet = onion_utils::construct_onion_packet_bogus_hopdata(new_payloads, onion_keys, [0; 32], &payment_hash); }, ||{}, false, Some(PERM|1), Some(msgs::HTLCFailChannelUpdate::ChannelClosed{short_channel_id: channels[1].0.contents.short_channel_id, is_permanent: true})); // the following three with run_onion_failure_test_with_fail_intercept() test only the origin node diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 4518dd72..09636cef 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -614,11 +614,6 @@ mod fuzzy_internal_msgs { pub(crate) enum OnionHopDataFormat { Legacy, // aka Realm-0 - // Some tests expect to be able to generate bogus non-deserializable OnionHopDatas. In the - // future we can use bogus TLV attributes, but for now we have to expose a "bogus realm" - // option. - #[cfg(test)] - BogusRealm(u8), } pub struct OnionHopData { @@ -968,8 +963,6 @@ impl Writeable for OnionHopData { w.size_hint(33); match self.format { OnionHopDataFormat::Legacy => 0u8.write(w)?, - #[cfg(test)] - OnionHopDataFormat::BogusRealm(v) => v.write(w)?, } self.short_channel_id.write(w)?; self.amt_to_forward.write(w)?; diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index fb968488..84e8d979 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -169,7 +169,19 @@ pub(super) fn construct_onion_packet(payloads: Vec, onion_ke construct_onion_packet_with_init_noise(payloads, onion_keys, packet_data, associated_data) } -fn construct_onion_packet_with_init_noise(mut payloads: Vec, onion_keys: Vec, mut packet_data: [u8; 20*65], associated_data: &PaymentHash) -> msgs::OnionPacket { +#[cfg(test)] +// Used in testing to write bogus OnionHopDatas, which is otherwise not representable in +// msgs::OnionHopData. +pub(super) fn construct_onion_packet_bogus_hopdata(payloads: Vec, onion_keys: Vec, prng_seed: [u8; 32], associated_data: &PaymentHash) -> msgs::OnionPacket { + let mut packet_data = [0; 20*65]; + + let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]); + chacha.process(&[0; 20*65], &mut packet_data); + + construct_onion_packet_with_init_noise(payloads, onion_keys, packet_data, associated_data) +} + +fn construct_onion_packet_with_init_noise(mut payloads: Vec, onion_keys: Vec, mut packet_data: [u8; 20*65], associated_data: &PaymentHash) -> msgs::OnionPacket { let mut buf = Vec::with_capacity(21*65); buf.resize(21*65, 0); -- 2.30.2