Skip to content

Commit e9bd893

Browse files
Fix debug panic in onion utils on large custom TLVs or metadata.
We previously assumed that the final node's payload would be ~93 bytes, and had code to ensure that the filler encoded after that payload is not all 0s. Now with custom TLVs and metadata supported, the final node's payload may take up the entire onion packet, so we can't assume that there are 64 bytes of filler to check.
1 parent ec8e0fe commit e9bd893

File tree

3 files changed

+77
-13
lines changed

3 files changed

+77
-13
lines changed

lightning/src/ln/onion_payment.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::prelude::*;
2323
use core::ops::Deref;
2424

2525
/// Invalid inbound onion payment.
26+
#[derive(Debug)]
2627
pub struct InboundOnionErr {
2728
/// BOLT 4 error code.
2829
pub err_code: u16,

lightning/src/ln/onion_utils.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1021,18 +1021,20 @@ fn decode_next_hop<T, R: ReadableArgs<T>, N: NextPacketBytes>(shared_secret: [u8
10211021
if hmac == [0; 32] {
10221022
#[cfg(test)]
10231023
{
1024-
// In tests, make sure that the initial onion packet data is, at least, non-0.
1025-
// We could do some fancy randomness test here, but, ehh, whatever.
1026-
// This checks for the issue where you can calculate the path length given the
1027-
// onion data as all the path entries that the originator sent will be here
1028-
// as-is (and were originally 0s).
1029-
// Of course reverse path calculation is still pretty easy given naive routing
1030-
// algorithms, but this fixes the most-obvious case.
1031-
let mut next_bytes = [0; 32];
1032-
chacha_stream.read_exact(&mut next_bytes).unwrap();
1033-
assert_ne!(next_bytes[..], [0; 32][..]);
1034-
chacha_stream.read_exact(&mut next_bytes).unwrap();
1035-
assert_ne!(next_bytes[..], [0; 32][..]);
1024+
if chacha_stream.read.position() < hop_data.len() as u64 - 64 {
1025+
// In tests, make sure that the initial onion packet data is, at least, non-0.
1026+
// We could do some fancy randomness test here, but, ehh, whatever.
1027+
// This checks for the issue where you can calculate the path length given the
1028+
// onion data as all the path entries that the originator sent will be here
1029+
// as-is (and were originally 0s).
1030+
// Of course reverse path calculation is still pretty easy given naive routing
1031+
// algorithms, but this fixes the most-obvious case.
1032+
let mut next_bytes = [0; 32];
1033+
chacha_stream.read_exact(&mut next_bytes).unwrap();
1034+
assert_ne!(next_bytes[..], [0; 32][..]);
1035+
chacha_stream.read_exact(&mut next_bytes).unwrap();
1036+
assert_ne!(next_bytes[..], [0; 32][..]);
1037+
}
10361038
}
10371039
return Ok((msg, None)); // We are the final destination for this packet
10381040
} else {

lightning/src/ln/payment_tests.rs

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, Mes
1919
use crate::ln::channel::{EXPIRE_PREV_CONFIG_TICKS, commit_tx_fee_msat, get_holder_selected_channel_reserve_satoshis, ANCHOR_OUTPUT_VALUE_SATOSHI};
2020
use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, RecentPaymentDetails, RecipientOnionFields, HTLCForwardInfo, PendingHTLCRouting, PendingAddHTLCInfo};
2121
use crate::ln::features::{Bolt11InvoiceFeatures, ChannelTypeFeatures};
22-
use crate::ln::{msgs, ChannelId, PaymentSecret, PaymentPreimage};
22+
use crate::ln::{msgs, ChannelId, PaymentHash, PaymentSecret, PaymentPreimage};
2323
use crate::ln::msgs::ChannelMessageHandler;
24+
use crate::ln::onion_utils;
2425
use crate::ln::outbound_payment::{IDEMPOTENCY_TIMEOUT_TICKS, Retry};
2526
use crate::routing::gossip::{EffectiveCapacity, RoutingFees};
2627
use crate::routing::router::{get_route, Path, PaymentParameters, Route, Router, RouteHint, RouteHintHop, RouteHop, RouteParameters, find_route};
@@ -31,10 +32,14 @@ use crate::util::errors::APIError;
3132
use crate::util::ser::Writeable;
3233
use crate::util::string::UntrustedString;
3334

35+
use bitcoin::hashes::Hash;
36+
use bitcoin::hashes::sha256::Hash as Sha256;
3437
use bitcoin::network::constants::Network;
38+
use bitcoin::secp256k1::{Secp256k1, SecretKey};
3539

3640
use crate::prelude::*;
3741

42+
use crate::ln::functional_test_utils;
3843
use crate::ln::functional_test_utils::*;
3944
use crate::routing::gossip::NodeId;
4045
#[cfg(feature = "std")]
@@ -4194,3 +4199,59 @@ fn test_htlc_forward_considers_anchor_outputs_value() {
41944199
check_closed_broadcast(&nodes[2], 1, true);
41954200
check_added_monitors(&nodes[2], 1);
41964201
}
4202+
4203+
#[test]
4204+
fn peel_payment_onion_custom_tlvs() {
4205+
let chanmon_cfgs = create_chanmon_cfgs(2);
4206+
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
4207+
let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, None]);
4208+
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
4209+
create_announced_chan_between_nodes(&nodes, 0, 1);
4210+
let secp_ctx = Secp256k1::new();
4211+
4212+
let amt_msat = 1000;
4213+
let payment_params = PaymentParameters::for_keysend(nodes[1].node.get_our_node_id(),
4214+
TEST_FINAL_CLTV, false);
4215+
let route_params = RouteParameters::from_payment_params_and_value(payment_params, amt_msat);
4216+
let route = functional_test_utils::get_route(&nodes[0], &route_params).unwrap();
4217+
let mut recipient_onion = RecipientOnionFields::spontaneous_empty()
4218+
.with_custom_tlvs(vec![(414141, vec![42; 1200])]).unwrap();
4219+
let prng_seed = chanmon_cfgs[0].keys_manager.get_secure_random_bytes();
4220+
let session_priv = SecretKey::from_slice(&prng_seed[..]).expect("RNG is busted");
4221+
let keysend_preimage = PaymentPreimage([42; 32]);
4222+
let payment_hash = PaymentHash(Sha256::hash(&keysend_preimage.0).to_byte_array());
4223+
4224+
let (onion_routing_packet, first_hop_msat, cltv_expiry) = onion_utils::create_payment_onion(
4225+
&secp_ctx, &route.paths[0], &session_priv, amt_msat, recipient_onion.clone(),
4226+
nodes[0].best_block_info().1, &payment_hash, &Some(keysend_preimage), prng_seed
4227+
).unwrap();
4228+
4229+
let update_add = msgs::UpdateAddHTLC {
4230+
channel_id: ChannelId([0; 32]),
4231+
htlc_id: 42,
4232+
amount_msat: first_hop_msat,
4233+
payment_hash,
4234+
cltv_expiry,
4235+
skimmed_fee_msat: None,
4236+
onion_routing_packet,
4237+
blinding_point: None,
4238+
};
4239+
let peeled_onion = crate::ln::onion_payment::peel_payment_onion(
4240+
&update_add, &&chanmon_cfgs[1].keys_manager, &&chanmon_cfgs[1].logger, &secp_ctx,
4241+
nodes[1].best_block_info().1, true, false
4242+
).unwrap();
4243+
assert_eq!(peeled_onion.incoming_amt_msat, Some(amt_msat));
4244+
match peeled_onion.routing {
4245+
PendingHTLCRouting::ReceiveKeysend {
4246+
payment_data, payment_metadata, custom_tlvs, ..
4247+
} => {
4248+
#[cfg(not(c_bindings))]
4249+
assert_eq!(&custom_tlvs, recipient_onion.custom_tlvs());
4250+
#[cfg(c_bindings)]
4251+
assert_eq!(custom_tlvs, recipient_onion.custom_tlvs());
4252+
assert!(payment_metadata.is_none());
4253+
assert!(payment_data.is_none());
4254+
},
4255+
_ => panic!()
4256+
}
4257+
}

0 commit comments

Comments
 (0)