Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lightning/src/offers/offer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2528,5 +2528,12 @@ mod bolt12_tests {
"lno1pgx9getnwss8vetrw3hhyucsespjgef743p5fzqq9nqxh0ah7y87rzv3ud0eleps9kl2d5348hq2k8qzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgqpqqqqqqqqqqqqqqqqqqqqqqqqqqqzqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqqzq3zyg3zyg3zygszqqqqyqqqqsqqvpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsq".parse::<Offer>(),
Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
);

// Bech32 padding exceeds 4-bit limit (BOLT 12 test vector)
// See: https://github.com/lightning/bolts/pull/1312
assert!(matches!(
"lno1zcss9mk8y3wkklfvevcrszlmu23kfrxh49px20665dqwmn4p72pkseseq".parse::<Offer>(),
Err(Bolt12ParseError::InvalidPadding(_))
));
}
}
30 changes: 28 additions & 2 deletions lightning/src/offers/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use crate::io;
use crate::ln::msgs::DecodeError;
use crate::util::ser::CursorReadable;
use bech32::primitives::decode::CheckedHrpstringError;
use bech32::primitives::decode::{CheckedHrpstringError, PaddingError};
use bitcoin::secp256k1;

#[allow(unused_imports)]
Expand Down Expand Up @@ -76,6 +76,10 @@ mod sealed {
return Err(Bolt12ParseError::InvalidBech32Hrp);
}

// Validate that bech32 padding is valid per BIP-173:
// "Any incomplete group at the end MUST be 4 bits or less, MUST be all zeroes"
parsed.validate_segwit_padding()?;

let data = parsed.byte_iter().collect::<Vec<u8>>();
Self::try_from(data)
}
Expand Down Expand Up @@ -146,6 +150,11 @@ pub enum Bolt12ParseError {
/// This is not exported to bindings users as the details don't matter much
CheckedHrpstringError,
),
/// The bech32 data has invalid padding per BIP-173 (more than 4 bits or non-zero padding).
InvalidPadding(
/// This is not exported to bindings users as the details don't matter much
PaddingError,
),
/// The bech32 decoded string could not be decoded as the expected message type.
Decode(DecodeError),
/// The parsed message has invalid semantics.
Expand Down Expand Up @@ -232,6 +241,12 @@ impl From<CheckedHrpstringError> for Bolt12ParseError {
}
}

impl From<PaddingError> for Bolt12ParseError {
fn from(error: PaddingError) -> Self {
Self::InvalidPadding(error)
}
}

impl From<DecodeError> for Bolt12ParseError {
fn from(error: DecodeError) -> Self {
Self::Decode(error)
Expand Down Expand Up @@ -326,7 +341,7 @@ mod bolt12_tests {

#[cfg(test)]
mod tests {
use super::Bolt12ParseError;
use super::{Bolt12ParseError, PaddingError};
use crate::ln::msgs::DecodeError;
use crate::offers::offer::Offer;
use bech32::primitives::decode::{CharError, CheckedHrpstringError, UncheckedHrpstringError};
Expand Down Expand Up @@ -371,4 +386,15 @@ mod tests {
Err(e) => assert_eq!(e, Bolt12ParseError::Decode(DecodeError::InvalidValue)),
}
}

#[test]
fn fails_parsing_bech32_encoded_offer_with_invalid_padding() {
// BOLT 12 test vector for invalid bech32 padding
// See: https://github.com/lightning/bolts/pull/1312
let encoded_offer = "lno1zcss9mk8y3wkklfvevcrszlmu23kfrxh49px20665dqwmn4p72pkseseq";
match encoded_offer.parse::<Offer>() {
Ok(_) => panic!("Valid offer: {}", encoded_offer),
Err(e) => assert_eq!(e, Bolt12ParseError::InvalidPadding(PaddingError::TooMuch)),
}
}
}
Loading