Skip to content

Commit 5494ddd

Browse files
Error if onion payloads exceed max length on packet construction.
Ensure that if we call construct_onion_packet and friends where payloads are too large for the allotted packet length, we'll fail to construct. Previously, senders would happily construct invalid packets by array-shifting the final node's HMAC out of the packet when adding an intermediate onion layer, causing the receiver to error with "final payload provided for us as an intermediate node."
1 parent 0e21ef5 commit 5494ddd

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

lightning/src/ln/onion_payment.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ pub(super) fn check_incoming_htlc_cltv(
442442
mod tests {
443443
use bitcoin::hashes::Hash;
444444
use bitcoin::hashes::sha256::Hash as Sha256;
445-
use bitcoin::secp256k1::{PublicKey, SecretKey};
445+
use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey};
446446
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
447447
use crate::ln::ChannelId;
448448
use crate::ln::channelmanager::RecipientOnionFields;
@@ -452,6 +452,38 @@ mod tests {
452452
use crate::routing::router::{Path, RouteHop};
453453
use crate::util::test_utils;
454454

455+
#[test]
456+
fn fail_construct_onion_on_too_big_payloads() {
457+
// Ensure that if we call `construct_onion_packet` and friends where payloads are too large for
458+
// the allotted packet length, we'll fail to construct. Previously, senders would happily
459+
// construct invalid packets by array-shifting the final node's HMAC out of the packet when
460+
// adding an intermediate onion layer, causing the receiver to error with "final payload
461+
// provided for us as an intermediate node."
462+
let secp_ctx = Secp256k1::new();
463+
let bob = crate::sign::KeysManager::new(&[2; 32], 42, 42);
464+
let bob_pk = PublicKey::from_secret_key(&secp_ctx, &bob.get_node_secret_key());
465+
let charlie = crate::sign::KeysManager::new(&[3; 32], 42, 42);
466+
let charlie_pk = PublicKey::from_secret_key(&secp_ctx, &charlie.get_node_secret_key());
467+
468+
let (
469+
session_priv, total_amt_msat, cur_height, mut recipient_onion, keysend_preimage, payment_hash,
470+
prng_seed, hops, ..
471+
) = payment_onion_args(bob_pk, charlie_pk);
472+
473+
// Ensure the onion will not fit all the payloads by adding a large custom TLV.
474+
recipient_onion.custom_tlvs.push((13377331, vec![0; 1156]));
475+
476+
let path = Path { hops, blinded_tail: None, };
477+
let onion_keys = super::onion_utils::construct_onion_keys(&secp_ctx, &path, &session_priv).unwrap();
478+
let (onion_payloads, ..) = super::onion_utils::build_onion_payloads(
479+
&path, total_amt_msat, recipient_onion, cur_height + 1, &Some(keysend_preimage)
480+
).unwrap();
481+
482+
assert!(super::onion_utils::construct_onion_packet(
483+
onion_payloads, onion_keys, prng_seed, &payment_hash
484+
).is_err());
485+
}
486+
455487
#[test]
456488
fn test_peel_payment_onion() {
457489
use super::*;

lightning/src/ln/onion_utils.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,15 @@ fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
322322
let mut res = Vec::with_capacity(ONION_HOP_DATA_LEN * (payloads.len() - 1));
323323

324324
let mut pos = 0;
325+
let mut packet_len_without_filler = 0;
325326
for (i, (payload, keys)) in payloads.iter().zip(onion_keys.iter()).enumerate() {
327+
let mut payload_len = LengthCalculatingWriter(0);
328+
payload.write(&mut payload_len).expect("Failed to calculate length");
329+
packet_len_without_filler += payload_len.0 + 32;
330+
if packet_len_without_filler > packet_data.len() {
331+
return Err(());
332+
}
333+
326334
if i == payloads.len() - 1 { break; }
327335

328336
let mut chacha = ChaCha20::new(&keys.rho, &[0u8; 8]);
@@ -331,13 +339,7 @@ fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
331339
chacha.process_in_place(&mut dummy); // We don't have a seek function :(
332340
}
333341

334-
let mut payload_len = LengthCalculatingWriter(0);
335-
payload.write(&mut payload_len).expect("Failed to calculate length");
336-
pos += payload_len.0 + 32;
337-
if pos > packet_data.len() {
338-
return Err(());
339-
}
340-
342+
pos = packet_len_without_filler;
341343
res.resize(pos, 0u8);
342344
chacha.process_in_place(&mut res);
343345
}

0 commit comments

Comments
 (0)