Skip to content

Commit b426301

Browse files
committed
Fix trampoline error packet encryption using trampoline shared secret
When handling HTLC failures in trampoline routing, error packets were not being properly encrypted with the trampoline shared secret. This caused error messages to be unreadable by the original sender when failures occurred within trampoline hops. The fix prioritizes trampoline_shared_secret over phantom_shared_secret when both are available, ensuring error packets can be properly decrypted by trampoline senders. Fixes the bug surfaced in test_trampoline_single_hop_receive in 39a98f5.
1 parent 907733f commit b426301

File tree

3 files changed

+45
-12
lines changed

3 files changed

+45
-12
lines changed

lightning/src/ln/blinded_payment_tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2041,8 +2041,8 @@ fn test_trampoline_forward_payload_encoded_as_receive() {
20412041
let path = [((carol_node_id, None), WithoutLength(&carol_unblinded_tlvs))];
20422042
blinded_path::utils::construct_blinded_hops(
20432043
&secp_ctx, path.into_iter(), &trampoline_session_priv,
2044-
).unwrap()
2045-
};
2044+
)
2045+
};
20462046

20472047
let route = Route {
20482048
paths: vec![Path {

lightning/src/ln/channelmanager.rs

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,9 @@ pub enum PendingHTLCRouting {
277277
/// provide the onion shared secret used to decrypt the next level of forwarding
278278
/// instructions.
279279
phantom_shared_secret: Option<[u8; 32]>,
280+
/// If the onion had trampoline forwarding instruction to our node.
281+
/// This will provice the onion shared secret to encrypt error packets to the sender.
282+
trampoline_shared_secret: Option<[u8; 32]>,
280283
/// Custom TLVs which were set by the sender.
281284
///
282285
/// For HTLCs received by LDK, this will ultimately be exposed in
@@ -466,6 +469,13 @@ impl PendingAddHTLCInfo {
466469
PendingHTLCRouting::Receive { phantom_shared_secret, .. } => phantom_shared_secret,
467470
_ => None,
468471
};
472+
let trampoline_shared_secret = match self.forward_info.routing {
473+
PendingHTLCRouting::Receive { trampoline_shared_secret, .. } => {
474+
trampoline_shared_secret
475+
},
476+
_ => None,
477+
};
478+
469479
HTLCPreviousHopData {
470480
short_channel_id: self.prev_short_channel_id,
471481
user_channel_id: Some(self.prev_user_channel_id),
@@ -475,6 +485,7 @@ impl PendingAddHTLCInfo {
475485
htlc_id: self.prev_htlc_id,
476486
incoming_packet_shared_secret: self.forward_info.incoming_shared_secret,
477487
phantom_shared_secret,
488+
trampoline_shared_secret,
478489
blinded_failure: self.forward_info.routing.blinded_failure(),
479490
cltv_expiry: self.forward_info.routing.incoming_cltv_expiry(),
480491
}
@@ -798,6 +809,7 @@ mod fuzzy_channelmanager {
798809
pub htlc_id: u64,
799810
pub incoming_packet_shared_secret: [u8; 32],
800811
pub phantom_shared_secret: Option<[u8; 32]>,
812+
pub trampoline_shared_secret: Option<[u8; 32]>,
801813
pub blinded_failure: Option<BlindedFailure>,
802814
pub channel_id: ChannelId,
803815

@@ -6835,14 +6847,16 @@ where
68356847
Some(payment_hash),
68366848
);
68376849
let mut failure_handler =
6838-
|msg, reason, err_data, phantom_ss, next_hop_unknown| {
6850+
|msg, reason, err_data, phantom_ss, trampoline_ss, next_hop_unknown| {
68396851
log_info!(logger, "Failed to accept/forward incoming HTLC: {}", msg);
68406852

68416853
let mut prev_hop = payment.htlc_previous_hop_data();
68426854
// Override the phantom shared secret because it wasn't set in the originating
68436855
// `PendingAddHTLCInfo` above, it was calculated below after detecting this as a
68446856
// phantom payment.
68456857
prev_hop.phantom_shared_secret = phantom_ss;
6858+
prev_hop.trampoline_shared_secret = trampoline_ss;
6859+
68466860
let failure_type = if next_hop_unknown {
68476861
HTLCHandlingFailureType::InvalidForward {
68486862
requested_forward_scid: short_chan_id,
@@ -6891,6 +6905,7 @@ where
68916905
reason,
68926906
sha256_of_onion.to_vec(),
68936907
None,
6908+
None,
68946909
false,
68956910
);
68966911
continue;
@@ -6907,6 +6922,7 @@ where
69076922
reason,
69086923
Vec::new(),
69096924
Some(phantom_shared_secret),
6925+
None,
69106926
false,
69116927
);
69126928
continue;
@@ -6940,6 +6956,7 @@ where
69406956
reason,
69416957
err_data,
69426958
Some(phantom_shared_secret),
6959+
None,
69436960
false,
69446961
);
69456962
continue;
@@ -6955,6 +6972,7 @@ where
69556972
LocalHTLCFailureReason::UnknownNextPeer,
69566973
Vec::new(),
69576974
None,
6975+
None,
69586976
true,
69596977
);
69606978
continue;
@@ -6967,6 +6985,7 @@ where
69676985
LocalHTLCFailureReason::UnknownNextPeer,
69686986
Vec::new(),
69696987
None,
6988+
None,
69706989
true,
69716990
);
69726991
continue;
@@ -7044,6 +7063,7 @@ where
70447063
panic!("short_channel_id != 0 should imply any pending_forward entries are of type Forward");
70457064
},
70467065
};
7066+
70477067
let next_blinding_point = blinded.and_then(|b| {
70487068
b.next_blinding_override.or_else(|| {
70497069
let encrypted_tlvs_ss = self
@@ -7276,13 +7296,15 @@ where
72767296
mut onion_fields,
72777297
has_recipient_created_payment_secret,
72787298
invoice_request_opt,
7299+
trampoline_shared_secret,
72797300
) = match routing {
72807301
PendingHTLCRouting::Receive {
72817302
payment_data,
72827303
payment_metadata,
72837304
payment_context,
72847305
incoming_cltv_expiry,
72857306
phantom_shared_secret,
7307+
trampoline_shared_secret,
72867308
custom_tlvs,
72877309
requires_blinded_error: _,
72887310
} => {
@@ -7301,6 +7323,7 @@ where
73017323
onion_fields,
73027324
true,
73037325
None,
7326+
trampoline_shared_secret,
73047327
)
73057328
},
73067329
PendingHTLCRouting::ReceiveKeysend {
@@ -7330,6 +7353,7 @@ where
73307353
onion_fields,
73317354
has_recipient_created_payment_secret,
73327355
invoice_request,
7356+
None,
73337357
)
73347358
},
73357359
_ => {
@@ -7377,6 +7401,7 @@ where
73777401
htlc_id: $htlc.prev_hop.htlc_id,
73787402
incoming_packet_shared_secret,
73797403
phantom_shared_secret,
7404+
trampoline_shared_secret,
73807405
blinded_failure,
73817406
cltv_expiry: Some(cltv_expiry),
73827407
}),
@@ -8176,6 +8201,7 @@ where
81768201
ref htlc_id,
81778202
ref incoming_packet_shared_secret,
81788203
ref phantom_shared_secret,
8204+
ref trampoline_shared_secret,
81798205
outpoint: _,
81808206
ref blinded_failure,
81818207
ref channel_id,
@@ -8188,6 +8214,7 @@ where
81888214
&payment_hash,
81898215
onion_error
81908216
);
8217+
let secondary_shared_secret = trampoline_shared_secret.or(*phantom_shared_secret);
81918218
let failure = match blinded_failure {
81928219
Some(BlindedFailure::FromIntroductionNode) => {
81938220
let blinded_onion_error = HTLCFailReason::reason(
@@ -8196,7 +8223,7 @@ where
81968223
);
81978224
let err_packet = blinded_onion_error.get_encrypted_failure_packet(
81988225
incoming_packet_shared_secret,
8199-
phantom_shared_secret,
8226+
&secondary_shared_secret,
82008227
);
82018228
HTLCForwardInfo::FailHTLC { htlc_id: *htlc_id, err_packet }
82028229
},
@@ -8208,7 +8235,7 @@ where
82088235
None => {
82098236
let err_packet = onion_error.get_encrypted_failure_packet(
82108237
incoming_packet_shared_secret,
8211-
phantom_shared_secret,
8238+
&secondary_shared_secret,
82128239
);
82138240
HTLCForwardInfo::FailHTLC { htlc_id: *htlc_id, err_packet }
82148241
},
@@ -8470,7 +8497,8 @@ where
84708497
ComplFunc: FnOnce(
84718498
Option<u64>,
84728499
bool,
8473-
) -> (Option<MonitorUpdateCompletionAction>, Option<RAAMonitorUpdateBlockingAction>),
8500+
)
8501+
-> (Option<MonitorUpdateCompletionAction>, Option<RAAMonitorUpdateBlockingAction>),
84748502
>(
84758503
&self, prev_hop: HTLCPreviousHopData, payment_preimage: PaymentPreimage,
84768504
payment_info: Option<PaymentClaimDetails>, attribution_data: Option<AttributionData>,
@@ -8508,7 +8536,8 @@ where
85088536
ComplFunc: FnOnce(
85098537
Option<u64>,
85108538
bool,
8511-
) -> (Option<MonitorUpdateCompletionAction>, Option<RAAMonitorUpdateBlockingAction>),
8539+
)
8540+
-> (Option<MonitorUpdateCompletionAction>, Option<RAAMonitorUpdateBlockingAction>),
85128541
>(
85138542
&self, prev_hop: HTLCClaimSource, payment_preimage: PaymentPreimage,
85148543
payment_info: Option<PaymentClaimDetails>, attribution_data: Option<AttributionData>,
@@ -15173,6 +15202,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
1517315202
(5, custom_tlvs, optional_vec),
1517415203
(7, requires_blinded_error, (default_value, false)),
1517515204
(9, payment_context, option),
15205+
(11, trampoline_shared_secret, option),
1517615206
},
1517715207
(2, ReceiveKeysend) => {
1517815208
(0, payment_preimage, required),
@@ -15301,6 +15331,7 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, {
1530115331
// filled in, so we can safely unwrap it here.
1530215332
(9, channel_id, (default_value, ChannelId::v1_from_funding_outpoint(outpoint.0.unwrap()))),
1530315333
(11, counterparty_node_id, option),
15334+
(13, trampoline_shared_secret, option),
1530415335
});
1530515336

1530615337
impl Writeable for ClaimableHTLC {

lightning/src/ln/onion_payment.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,14 @@ pub(super) fn create_recv_pending_htlc_info(
253253
let (
254254
payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, onion_cltv_expiry,
255255
payment_metadata, payment_context, requires_blinded_error, has_recipient_created_payment_secret,
256-
invoice_request
256+
invoice_request, trampoline_shared_secret,
257257
) = match hop_data {
258258
onion_utils::Hop::Receive { hop_data: msgs::InboundOnionReceivePayload {
259259
payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
260260
cltv_expiry_height, payment_metadata, ..
261261
}, .. } =>
262262
(payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
263-
cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None),
263+
cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None, None),
264264
onion_utils::Hop::BlindedReceive { hop_data: msgs::InboundOnionBlindedReceivePayload {
265265
sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
266266
intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
@@ -279,7 +279,7 @@ pub(super) fn create_recv_pending_htlc_info(
279279
let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
280280
(Some(payment_data), keysend_preimage, custom_tlvs,
281281
sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context),
282-
intro_node_blinding_point.is_none(), true, invoice_request)
282+
intro_node_blinding_point.is_none(), true, invoice_request, None)
283283
}
284284
onion_utils::Hop::TrampolineReceive {
285285
trampoline_hop_data: msgs::InboundOnionReceivePayload {
@@ -288,8 +288,9 @@ pub(super) fn create_recv_pending_htlc_info(
288288
}, ..
289289
} =>
290290
(payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat,
291-
cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None),
291+
cltv_expiry_height, payment_metadata, None, false, keysend_preimage.is_none(), None, None),
292292
onion_utils::Hop::TrampolineBlindedReceive {
293+
trampoline_shared_secret,
293294
trampoline_hop_data: msgs::InboundOnionBlindedReceivePayload {
294295
sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret,
295296
intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage,
@@ -309,7 +310,7 @@ pub(super) fn create_recv_pending_htlc_info(
309310
let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat };
310311
(Some(payment_data), keysend_preimage, custom_tlvs,
311312
sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context),
312-
intro_node_blinding_point.is_none(), true, invoice_request)
313+
intro_node_blinding_point.is_none(), true, invoice_request, Some(trampoline_shared_secret.secret_bytes()))
313314
},
314315
onion_utils::Hop::Forward { .. } => {
315316
return Err(InboundHTLCErr {
@@ -398,6 +399,7 @@ pub(super) fn create_recv_pending_htlc_info(
398399
payment_context,
399400
incoming_cltv_expiry: onion_cltv_expiry,
400401
phantom_shared_secret,
402+
trampoline_shared_secret,
401403
custom_tlvs,
402404
requires_blinded_error,
403405
}

0 commit comments

Comments
 (0)