Skip to content

Commit 2de1c6a

Browse files
f check for invalid provided blinded payment TLVs
1 parent 89b33bb commit 2de1c6a

File tree

2 files changed

+64
-3
lines changed

2 files changed

+64
-3
lines changed

lightning/src/blinded_path/mod.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,25 @@ impl BlindedPath {
8080
/// Create a blinded path for a payment, to be forwarded along `path`. The last node
8181
/// in `path` will be the destination node.
8282
///
83-
/// Errors if `path` is empty, a node id in `path` is invalid, or [`BlindedPayInfo`] calculation
84-
/// results in an integer overflow.
83+
/// Errors if:
84+
/// * `path` is empty
85+
/// * a node id in `path` is invalid
86+
/// * [`BlindedPayInfo`] calculation results in an integer overflow
87+
/// * the list of [`BlindedPaymentTlvs`] does not consist of 0 or more
88+
/// `BlindedPaymentTlvs::Forward` followed by 1 `BlindedPaymentTlvs::Receive`
8589
// TODO: make all payloads the same size with padding + add dummy hops
8690
pub fn new_for_payment<ES: EntropySource, T: secp256k1::Signing + secp256k1::Verification>(
8791
path: &[(PublicKey, BlindedPaymentTlvs)], entropy_source: &ES, secp_ctx: &Secp256k1<T>
8892
) -> Result<(BlindedPayInfo, Self), ()> {
8993
if path.len() < 1 { return Err(()) }
94+
let mut found_recv_payload = false;
95+
for (_, payload) in path.iter() {
96+
if let BlindedPaymentTlvs::Receive { .. } = payload {
97+
if found_recv_payload { return Err(()) }
98+
found_recv_payload = true;
99+
} else if found_recv_payload { return Err(()) }
100+
}
101+
90102
let blinding_secret_bytes = entropy_source.get_secure_random_bytes();
91103
let blinding_secret = SecretKey::from_slice(&blinding_secret_bytes[..]).expect("RNG is busted");
92104

lightning/src/blinded_path/payment.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,10 +210,13 @@ impl_writeable_msg!(PaymentConstraints, {
210210

211211
#[cfg(test)]
212212
mod tests {
213-
use bitcoin::secp256k1::PublicKey;
213+
use bitcoin::network::constants::Network;
214+
use bitcoin::secp256k1::{PublicKey, Secp256k1};
215+
use crate::blinded_path::BlindedPath;
214216
use crate::blinded_path::payment::{BlindedPaymentTlvs, PaymentConstraints, PaymentRelay};
215217
use crate::ln::PaymentSecret;
216218
use crate::ln::features::BlindedHopFeatures;
219+
use crate::util::test_utils;
217220

218221
#[test]
219222
fn compute_payinfo() {
@@ -275,4 +278,50 @@ mod tests {
275278
assert_eq!(blinded_payinfo.cltv_expiry_delta, 0);
276279
assert_eq!(blinded_payinfo.htlc_minimum_msat, 1);
277280
}
281+
282+
#[test]
283+
fn invalid_payloads() {
284+
let dummy_pk = PublicKey::from_slice(&[2; 33]).unwrap();
285+
let secp_ctx = Secp256k1::new();
286+
let keys_manager = test_utils::TestKeysInterface::new(&[42 as u8; 32], Network::Testnet);
287+
288+
let out_of_order_payloads_path = vec![(dummy_pk, BlindedPaymentTlvs::Receive {
289+
payment_secret: PaymentSecret([0; 32]),
290+
payment_constraints: PaymentConstraints {
291+
max_cltv_expiry: 0,
292+
htlc_minimum_msat: 1,
293+
},
294+
features: BlindedHopFeatures::empty(),
295+
}), (dummy_pk, BlindedPaymentTlvs::Forward {
296+
short_channel_id: 0,
297+
payment_relay: PaymentRelay {
298+
cltv_expiry_delta: 144,
299+
fee_proportional_millionths: 500,
300+
fee_base_msat: 100,
301+
},
302+
payment_constraints: PaymentConstraints {
303+
max_cltv_expiry: 0,
304+
htlc_minimum_msat: 100,
305+
},
306+
features: BlindedHopFeatures::empty(),
307+
})];
308+
assert!(BlindedPath::new_for_payment(&out_of_order_payloads_path[..], &keys_manager, &secp_ctx).is_err());
309+
310+
let multiple_recv_payloads_path = vec![(dummy_pk, BlindedPaymentTlvs::Receive {
311+
payment_secret: PaymentSecret([0; 32]),
312+
payment_constraints: PaymentConstraints {
313+
max_cltv_expiry: 0,
314+
htlc_minimum_msat: 1,
315+
},
316+
features: BlindedHopFeatures::empty(),
317+
}), (dummy_pk, BlindedPaymentTlvs::Receive {
318+
payment_secret: PaymentSecret([0; 32]),
319+
payment_constraints: PaymentConstraints {
320+
max_cltv_expiry: 0,
321+
htlc_minimum_msat: 1,
322+
},
323+
features: BlindedHopFeatures::empty(),
324+
})];
325+
assert!(BlindedPath::new_for_payment(&multiple_recv_payloads_path[..], &keys_manager, &secp_ctx).is_err());
326+
}
278327
}

0 commit comments

Comments
 (0)