X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=6c1d3cd928700a13550327c87d47b6fe1d634577;hb=eff8af21103e43f763cb10ae6a75c1543a2d4068;hp=294dbb965e781aebdfa90bcb00ca4e2fff081755;hpb=b54817397d62817d806d2ac266617ef30709d1d3;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 294dbb96..6c1d3cd9 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -15,15 +15,14 @@ //! raw socket events into your non-internet-facing system and then send routing events back to //! track the network on the less-secure system. -use secp256k1::key::PublicKey; -use secp256k1::Signature; -use secp256k1; -use bitcoin_hashes::sha256d::Hash as Sha256dHash; +use bitcoin::secp256k1::key::PublicKey; +use bitcoin::secp256k1::Signature; +use bitcoin::secp256k1; +use bitcoin::hashes::sha256d::Hash as Sha256dHash; use bitcoin::blockdata::script::Script; use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; -use std::error::Error; use std::{cmp, fmt}; use std::io::Read; use std::result::Result; @@ -31,7 +30,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)] @@ -612,11 +614,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: [u8; 32], + pub(crate) payment_secret: PaymentSecret, + /// The total value, in msat, of the payment as received by the ultimate recipient. + /// Message serialization may panic if this value is more than 21 million Bitcoin. pub(crate) total_msat: u64, } @@ -634,6 +640,8 @@ mod fuzzy_internal_msgs { pub struct OnionHopData { pub(crate) format: OnionHopDataFormat, + /// The value, in msat, of the payment after this hop's fee is deducted. + /// Message serialization may panic if this value is more than 21 million Bitcoin. pub(crate) amt_to_forward: u64, pub(crate) outgoing_cltv_value: u32, // 12 bytes of 0-padding for Legacy format @@ -679,21 +687,16 @@ pub(crate) struct OnionErrorPacket { pub(crate) data: Vec, } -impl Error for DecodeError { - fn description(&self) -> &str { - match *self { - DecodeError::UnknownVersion => "Unknown realm byte in Onion packet", - DecodeError::UnknownRequiredFeature => "Unknown required feature preventing decode", - DecodeError::InvalidValue => "Nonsense bytes didn't map to the type they were interpreted as", - DecodeError::ShortRead => "Packet extended beyond the provided bytes", - DecodeError::BadLengthDescriptor => "A length descriptor in the packet didn't describe the later data correctly", - DecodeError::Io(ref e) => e.description(), - } - } -} impl fmt::Display for DecodeError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str(self.description()) + match *self { + DecodeError::UnknownVersion => f.write_str("Unknown realm byte in Onion packet"), + DecodeError::UnknownRequiredFeature => f.write_str("Unknown required feature preventing decode"), + DecodeError::InvalidValue => f.write_str("Nonsense bytes didn't map to the type they were interpreted as"), + DecodeError::ShortRead => f.write_str("Packet extended beyond the provided bytes"), + DecodeError::BadLengthDescriptor => f.write_str("A length descriptor in the packet didn't describe the later data correctly"), + DecodeError::Io(ref e) => e.fmt(f), + } } } @@ -975,22 +978,26 @@ impl_writeable!(UpdateAddHTLC, 32+8+8+32+4+1366, { 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.write(w)?; + self.payment_secret.0.write(w)?; HighZeroBytesDroppedVarInt(self.total_msat).write(w) } } impl Readable for FinalOnionHopData { fn read(r: &mut R) -> Result { - let payment_secret = Readable::read(r)?; + let secret: [u8; 32] = Readable::read(r)?; let amt: HighZeroBytesDroppedVarInt = Readable::read(r)?; - Ok(Self { payment_secret, total_msat: amt.0 }) + 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); + // Note that this should never be reachable if Rust-Lightning generated the message, as we + // check values are sane long before we get here, though its possible in the future + // user-generated messages may hit this. + if self.amt_to_forward > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); } match self.format { OnionHopDataFormat::Legacy { short_channel_id } => { 0u8.write(w)?; @@ -1007,6 +1014,7 @@ impl Writeable for OnionHopData { }); }, OnionHopDataFormat::FinalNode { payment_data: Some(ref final_data) } => { + if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); } encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)), (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)), @@ -1053,6 +1061,11 @@ impl Readable for OnionHopData { short_channel_id, } } else { + if let &Some(ref data) = &payment_data { + if data.total_msat > MAX_VALUE_MSAT { + return Err(DecodeError::InvalidValue); + } + } OnionHopDataFormat::FinalNode { payment_data } @@ -1068,6 +1081,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, @@ -1341,18 +1357,18 @@ mod tests { use hex; use ln::msgs; use ln::msgs::{ChannelFeatures, FinalOnionHopData, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket, OnionHopDataFormat}; - use ln::channelmanager::{PaymentPreimage, PaymentHash}; + use ln::channelmanager::{PaymentPreimage, PaymentHash, PaymentSecret}; use util::ser::{Writeable, Readable}; - use bitcoin_hashes::sha256d::Hash as Sha256dHash; - use bitcoin_hashes::hex::FromHex; + use bitcoin::hashes::sha256d::Hash as Sha256dHash; + use bitcoin::hashes::hex::FromHex; use bitcoin::util::address::Address; use bitcoin::network::constants::Network; use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; - use secp256k1::key::{PublicKey,SecretKey}; - use secp256k1::{Secp256k1, Message}; + use bitcoin::secp256k1::key::{PublicKey,SecretKey}; + use bitcoin::secp256k1::{Secp256k1, Message}; use std::io::Cursor; @@ -2050,7 +2066,7 @@ mod tests { #[test] fn encoding_final_onion_hop_data_with_secret() { - let expected_payment_secret = [0x42u8; 32]; + let expected_payment_secret = PaymentSecret([0x42u8; 32]); let mut msg = msgs::OnionHopData { format: OnionHopDataFormat::FinalNode { payment_data: Some(FinalOnionHopData {