X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;ds=inline;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=4bdde0f4bcb9799913b873443f0e71677b691f45;hb=03a1b5264de8ec59bd274d7d6372bc7ad7eb4a03;hp=1ad798fd4bfaf2417d20fdeb4030dd876d7dd77c;hpb=c2ca6d3cdc7810c6b2e40013dd0355fd1268a519;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 1ad798fd..4bdde0f4 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -31,7 +31,10 @@ use std::result::Result; use util::events; use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt}; -use ln::channelmanager::{PaymentPreimage, PaymentHash}; +use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret}; + +/// 21 million * 10^8 * 1000 +pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000; /// An error in decoding a message or struct. #[derive(Debug)] @@ -601,7 +604,7 @@ pub trait RoutingMessageHandler : Send + Sync { /// Gets a subset of the channel announcements and updates required to dump our routing table /// to a remote node, starting at the short_channel_id indicated by starting_point and /// including the batch_amount entries immediately higher in numerical value than starting_point. - fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(ChannelAnnouncement, ChannelUpdate, ChannelUpdate)>; + fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(ChannelAnnouncement, Option, Option)>; /// Gets a subset of the node announcements required to dump our routing table to a remote node, /// starting at the node *after* the provided publickey and including batch_amount entries /// immediately higher (as defined by ::cmp) than starting_point. @@ -612,8 +615,15 @@ pub trait RoutingMessageHandler : Send + Sync { } mod fuzzy_internal_msgs { + use ln::channelmanager::PaymentSecret; + // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize // them from untrusted input): + #[derive(Clone)] + pub(crate) struct FinalOnionHopData { + pub(crate) payment_secret: PaymentSecret, + pub(crate) total_msat: u64, + } pub(crate) enum OnionHopDataFormat { Legacy { // aka Realm-0 @@ -622,7 +632,9 @@ mod fuzzy_internal_msgs { NonFinalNode { short_channel_id: u64, }, - FinalNode, + FinalNode { + payment_data: Option, + }, } pub struct OnionHopData { @@ -965,6 +977,22 @@ impl_writeable!(UpdateAddHTLC, 32+8+8+32+4+1366, { onion_routing_packet }); +impl Writeable for FinalOnionHopData { + fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { + w.size_hint(32 + 8 - (self.total_msat.leading_zeros()/8) as usize); + self.payment_secret.0.write(w)?; + HighZeroBytesDroppedVarInt(self.total_msat).write(w) + } +} + +impl Readable for FinalOnionHopData { + fn read(r: &mut R) -> Result { + let secret: [u8; 32] = Readable::read(r)?; + let amt: HighZeroBytesDroppedVarInt = Readable::read(r)?; + Ok(Self { payment_secret: PaymentSecret(secret), total_msat: amt.0 }) + } +} + impl Writeable for OnionHopData { fn write(&self, w: &mut W) -> Result<(), ::std::io::Error> { w.size_hint(33); @@ -983,7 +1011,14 @@ impl Writeable for OnionHopData { (6, short_channel_id) }); }, - OnionHopDataFormat::FinalNode => { + OnionHopDataFormat::FinalNode { payment_data: Some(ref final_data) } => { + encode_varint_length_prefixed_tlv!(w, { + (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)), + (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)), + (8, final_data) + }); + }, + OnionHopDataFormat::FinalNode { payment_data: None } => { encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)), (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)) @@ -1008,19 +1043,29 @@ impl Readable for OnionHopData { let mut amt = HighZeroBytesDroppedVarInt(0u64); let mut cltv_value = HighZeroBytesDroppedVarInt(0u32); let mut short_id: Option = None; + let mut payment_data: Option = None; decode_tlv!(&mut rd, { (2, amt), (4, cltv_value) }, { - (6, short_id) + (6, short_id), + (8, payment_data) }); rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?; let format = if let Some(short_channel_id) = short_id { + if payment_data.is_some() { return Err(DecodeError::InvalidValue); } OnionHopDataFormat::NonFinalNode { short_channel_id, } } else { - OnionHopDataFormat::FinalNode + if let &Some(ref data) = &payment_data { + if data.total_msat > MAX_VALUE_MSAT { + return Err(DecodeError::InvalidValue); + } + } + OnionHopDataFormat::FinalNode { + payment_data + } }; (format, amt.0, cltv_value.0) } else { @@ -1033,6 +1078,9 @@ impl Readable for OnionHopData { (format, amt, cltv_value) }; + if amt > MAX_VALUE_MSAT { + return Err(DecodeError::InvalidValue); + } Ok(OnionHopData { format, amt_to_forward: amt, @@ -1305,8 +1353,8 @@ impl_writeable_len_match!(NodeAnnouncement, { mod tests { use hex; use ln::msgs; - use ln::msgs::{ChannelFeatures, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket, OnionHopDataFormat}; - use ln::channelmanager::{PaymentPreimage, PaymentHash}; + use ln::msgs::{ChannelFeatures, FinalOnionHopData, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket, OnionHopDataFormat}; + use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret}; use util::ser::{Writeable, Readable}; use bitcoin_hashes::sha256d::Hash as Sha256dHash; @@ -1998,7 +2046,9 @@ mod tests { #[test] fn encoding_final_onion_hop_data() { let mut msg = msgs::OnionHopData { - format: OnionHopDataFormat::FinalNode, + format: OnionHopDataFormat::FinalNode { + payment_data: None, + }, amt_to_forward: 0x0badf00d01020304, outgoing_cltv_value: 0xffffffff, }; @@ -2006,7 +2056,36 @@ mod tests { let target_value = hex::decode("1002080badf00d010203040404ffffffff").unwrap(); assert_eq!(encoded_value, target_value); msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap(); - if let OnionHopDataFormat::FinalNode = msg.format { } else { panic!(); } + if let OnionHopDataFormat::FinalNode { payment_data: None } = msg.format { } else { panic!(); } + assert_eq!(msg.amt_to_forward, 0x0badf00d01020304); + assert_eq!(msg.outgoing_cltv_value, 0xffffffff); + } + + #[test] + fn encoding_final_onion_hop_data_with_secret() { + let expected_payment_secret = PaymentSecret([0x42u8; 32]); + let mut msg = msgs::OnionHopData { + format: OnionHopDataFormat::FinalNode { + payment_data: Some(FinalOnionHopData { + payment_secret: expected_payment_secret, + total_msat: 0x1badca1f + }), + }, + amt_to_forward: 0x0badf00d01020304, + outgoing_cltv_value: 0xffffffff, + }; + let encoded_value = msg.encode(); + let target_value = hex::decode("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap(); + assert_eq!(encoded_value, target_value); + msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap(); + if let OnionHopDataFormat::FinalNode { + payment_data: Some(FinalOnionHopData { + payment_secret, + total_msat: 0x1badca1f + }) + } = msg.format { + assert_eq!(payment_secret, expected_payment_secret); + } else { panic!(); } assert_eq!(msg.amt_to_forward, 0x0badf00d01020304); assert_eq!(msg.outgoing_cltv_value, 0xffffffff); }