Skip to content

Commit 99073c7

Browse files
authored
Merge pull request #1324 from valentinewallace/2022-02-phantom-followup
#1199 Followup
2 parents 78174f3 + 694ef1e commit 99073c7

File tree

5 files changed

+479
-46
lines changed

5 files changed

+479
-46
lines changed

fuzz/src/full_stack.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,9 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
390390
best_block: BestBlock::from_genesis(network),
391391
};
392392
let channelmanager = Arc::new(ChannelManager::new(fee_est.clone(), monitor.clone(), broadcast.clone(), Arc::clone(&logger), keys_manager.clone(), config, params));
393+
// Adding new calls to `KeysInterface::get_secure_random_bytes` during startup can change all the
394+
// keys subsequently generated in this test. Rather than regenerating all the messages manually,
395+
// it's easier to just increment the counter here so the keys don't change.
393396
keys_manager.counter.fetch_sub(1, Ordering::AcqRel);
394397
let our_id = PublicKey::from_secret_key(&Secp256k1::signing_only(), &keys_manager.get_node_secret(Recipient::Node).unwrap());
395398
let network_graph = Arc::new(NetworkGraph::new(genesis_block(network).block_hash()));

lightning/src/ln/channelmanager.rs

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -358,14 +358,15 @@ mod inbound_payment {
358358
// our payment, which we can use to decode errors or inform the user that the payment was sent.
359359

360360
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
361-
enum PendingHTLCRouting {
361+
pub(super) enum PendingHTLCRouting {
362362
Forward {
363363
onion_packet: msgs::OnionPacket,
364364
short_channel_id: u64, // This should be NonZero<u64> eventually when we bump MSRV
365365
},
366366
Receive {
367367
payment_data: msgs::FinalOnionHopData,
368368
incoming_cltv_expiry: u32, // Used to track when we should expire pending HTLCs that go unclaimed
369+
phantom_shared_secret: Option<[u8; 32]>,
369370
},
370371
ReceiveKeysend {
371372
payment_preimage: PaymentPreimage,
@@ -375,8 +376,8 @@ enum PendingHTLCRouting {
375376

376377
#[derive(Clone)] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
377378
pub(super) struct PendingHTLCInfo {
378-
routing: PendingHTLCRouting,
379-
incoming_shared_secret: [u8; 32],
379+
pub(super) routing: PendingHTLCRouting,
380+
pub(super) incoming_shared_secret: [u8; 32],
380381
payment_hash: PaymentHash,
381382
pub(super) amt_to_forward: u64,
382383
pub(super) outgoing_cltv_value: u32,
@@ -419,6 +420,7 @@ pub(crate) struct HTLCPreviousHopData {
419420
short_channel_id: u64,
420421
htlc_id: u64,
421422
incoming_packet_shared_secret: [u8; 32],
423+
phantom_shared_secret: Option<[u8; 32]>,
422424

423425
// This field is consumed by `claim_funds_from_hop()` when updating a force-closed backwards
424426
// channel with a preimage provided by the forward channel.
@@ -2072,7 +2074,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
20722074
}
20732075

20742076
fn construct_recv_pending_htlc_info(&self, hop_data: msgs::OnionHopData, shared_secret: [u8; 32],
2075-
payment_hash: PaymentHash, amt_msat: u64, cltv_expiry: u32) -> Result<PendingHTLCInfo, ReceiveError>
2077+
payment_hash: PaymentHash, amt_msat: u64, cltv_expiry: u32, phantom_shared_secret: Option<[u8; 32]>) -> Result<PendingHTLCInfo, ReceiveError>
20762078
{
20772079
// final_incorrect_cltv_expiry
20782080
if hop_data.outgoing_cltv_value != cltv_expiry {
@@ -2129,6 +2131,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
21292131
PendingHTLCRouting::Receive {
21302132
payment_data: data,
21312133
incoming_cltv_expiry: hop_data.outgoing_cltv_value,
2134+
phantom_shared_secret,
21322135
}
21332136
} else if let Some(payment_preimage) = keysend_preimage {
21342137
// We need to check that the sender knows the keysend preimage before processing this
@@ -2232,7 +2235,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
22322235
let pending_forward_info = match next_hop {
22332236
onion_utils::Hop::Receive(next_hop_data) => {
22342237
// OUR PAYMENT!
2235-
match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry) {
2238+
match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, None) {
22362239
Ok(info) => {
22372240
// Note that we could obviously respond immediately with an update_fulfill_htlc
22382241
// message, however that would leak that we are the recipient of this payment, so
@@ -3012,17 +3015,18 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
30123015
routing, incoming_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value },
30133016
prev_funding_outpoint } => {
30143017
macro_rules! fail_forward {
3015-
($msg: expr, $err_code: expr, $err_data: expr) => {
3018+
($msg: expr, $err_code: expr, $err_data: expr, $phantom_ss: expr) => {
30163019
{
30173020
log_info!(self.logger, "Failed to accept/forward incoming HTLC: {}", $msg);
30183021
let htlc_source = HTLCSource::PreviousHopData(HTLCPreviousHopData {
3019-
short_channel_id: short_chan_id,
3022+
short_channel_id: prev_short_channel_id,
30203023
outpoint: prev_funding_outpoint,
30213024
htlc_id: prev_htlc_id,
30223025
incoming_packet_shared_secret: incoming_shared_secret,
3026+
phantom_shared_secret: $phantom_ss,
30233027
});
30243028
failed_forwards.push((htlc_source, payment_hash,
3025-
HTLCFailReason::Reason { failure_code: $err_code, data: $err_data }
3029+
HTLCFailReason::Reason { failure_code: $err_code, data: $err_data }
30263030
));
30273031
continue;
30283032
}
@@ -3031,44 +3035,46 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
30313035
if let PendingHTLCRouting::Forward { onion_packet, .. } = routing {
30323036
let phantom_secret_res = self.keys_manager.get_node_secret(Recipient::PhantomNode);
30333037
if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id) {
3034-
let shared_secret = {
3038+
let phantom_shared_secret = {
30353039
let mut arr = [0; 32];
30363040
arr.copy_from_slice(&SharedSecret::new(&onion_packet.public_key.unwrap(), &phantom_secret_res.unwrap())[..]);
30373041
arr
30383042
};
3039-
let next_hop = match onion_utils::decode_next_hop(shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
3043+
let next_hop = match onion_utils::decode_next_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
30403044
Ok(res) => res,
30413045
Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => {
3042-
fail_forward!(err_msg, err_code, Vec::new());
3046+
let sha256_of_onion = Sha256::hash(&onion_packet.hop_data).into_inner();
3047+
// In this scenario, the phantom would have sent us an
3048+
// `update_fail_malformed_htlc`, meaning here we encrypt the error as
3049+
// if it came from us (the second-to-last hop) but contains the sha256
3050+
// of the onion.
3051+
fail_forward!(err_msg, err_code, sha256_of_onion.to_vec(), None);
30433052
},
30443053
Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => {
3045-
fail_forward!(err_msg, err_code, Vec::new());
3054+
fail_forward!(err_msg, err_code, Vec::new(), Some(phantom_shared_secret));
30463055
},
30473056
};
30483057
match next_hop {
30493058
onion_utils::Hop::Receive(hop_data) => {
3050-
match self.construct_recv_pending_htlc_info(hop_data, shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value) {
3059+
match self.construct_recv_pending_htlc_info(hop_data, incoming_shared_secret, payment_hash, amt_to_forward, outgoing_cltv_value, Some(phantom_shared_secret)) {
30513060
Ok(info) => phantom_receives.push((prev_short_channel_id, prev_funding_outpoint, vec![(info, prev_htlc_id)])),
3052-
Err(ReceiveError { err_code, err_data, msg }) => fail_forward!(msg, err_code, err_data)
3061+
Err(ReceiveError { err_code, err_data, msg }) => fail_forward!(msg, err_code, err_data, Some(phantom_shared_secret))
30533062
}
30543063
},
30553064
_ => panic!(),
30563065
}
30573066
} else {
3058-
fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new());
3067+
fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new(), None);
30593068
}
30603069
} else {
3061-
fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new());
3070+
fail_forward!(format!("Unknown short channel id {} for forward HTLC", short_chan_id), 0x4000 | 10, Vec::new(), None);
30623071
}
30633072
},
30643073
HTLCForwardInfo::FailHTLC { .. } => {
30653074
// Channel went away before we could fail it. This implies
30663075
// the channel is now on chain and our counterparty is
30673076
// trying to broadcast the HTLC-Timeout, but that's their
30683077
// problem, not ours.
3069-
//
3070-
// `fail_htlc_backwards_internal` is never called for
3071-
// phantom payments, so this is unreachable for them.
30723078
}
30733079
}
30743080
}
@@ -3091,6 +3097,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
30913097
outpoint: prev_funding_outpoint,
30923098
htlc_id: prev_htlc_id,
30933099
incoming_packet_shared_secret: incoming_shared_secret,
3100+
// Phantom payments are only PendingHTLCRouting::Receive.
3101+
phantom_shared_secret: None,
30943102
});
30953103
match chan.get_mut().send_htlc(amt_to_forward, payment_hash, outgoing_cltv_value, htlc_source.clone(), onion_packet, &self.logger) {
30963104
Err(e) => {
@@ -3207,11 +3215,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32073215
HTLCForwardInfo::AddHTLC { prev_short_channel_id, prev_htlc_id, forward_info: PendingHTLCInfo {
32083216
routing, incoming_shared_secret, payment_hash, amt_to_forward, .. },
32093217
prev_funding_outpoint } => {
3210-
let (cltv_expiry, onion_payload) = match routing {
3211-
PendingHTLCRouting::Receive { payment_data, incoming_cltv_expiry } =>
3212-
(incoming_cltv_expiry, OnionPayload::Invoice(payment_data)),
3218+
let (cltv_expiry, onion_payload, phantom_shared_secret) = match routing {
3219+
PendingHTLCRouting::Receive { payment_data, incoming_cltv_expiry, phantom_shared_secret } =>
3220+
(incoming_cltv_expiry, OnionPayload::Invoice(payment_data), phantom_shared_secret),
32133221
PendingHTLCRouting::ReceiveKeysend { payment_preimage, incoming_cltv_expiry } =>
3214-
(incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage)),
3222+
(incoming_cltv_expiry, OnionPayload::Spontaneous(payment_preimage), None),
32153223
_ => {
32163224
panic!("short_channel_id == 0 should imply any pending_forward entries are of type Receive");
32173225
}
@@ -3222,6 +3230,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32223230
outpoint: prev_funding_outpoint,
32233231
htlc_id: prev_htlc_id,
32243232
incoming_packet_shared_secret: incoming_shared_secret,
3233+
phantom_shared_secret,
32253234
},
32263235
value: amt_to_forward,
32273236
cltv_expiry,
@@ -3239,6 +3248,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
32393248
outpoint: prev_funding_outpoint,
32403249
htlc_id: $htlc.prev_hop.htlc_id,
32413250
incoming_packet_shared_secret: $htlc.prev_hop.incoming_packet_shared_secret,
3251+
phantom_shared_secret,
32423252
}), payment_hash,
32433253
HTLCFailReason::Reason { failure_code: 0x4000 | 15, data: htlc_msat_height_data }
32443254
));
@@ -3778,12 +3788,18 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
37783788
pending_events.push(path_failure);
37793789
if let Some(ev) = full_failure_ev { pending_events.push(ev); }
37803790
},
3781-
HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret, .. }) => {
3791+
HTLCSource::PreviousHopData(HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret, phantom_shared_secret, .. }) => {
37823792
let err_packet = match onion_error {
37833793
HTLCFailReason::Reason { failure_code, data } => {
37843794
log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards from us with code {}", log_bytes!(payment_hash.0), failure_code);
3785-
let packet = onion_utils::build_failure_packet(&incoming_packet_shared_secret, failure_code, &data[..]).encode();
3786-
onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &packet)
3795+
if let Some(phantom_ss) = phantom_shared_secret {
3796+
let phantom_packet = onion_utils::build_failure_packet(&phantom_ss, failure_code, &data[..]).encode();
3797+
let encrypted_phantom_packet = onion_utils::encrypt_failure_packet(&phantom_ss, &phantom_packet);
3798+
onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &encrypted_phantom_packet.data[..])
3799+
} else {
3800+
let packet = onion_utils::build_failure_packet(&incoming_packet_shared_secret, failure_code, &data[..]).encode();
3801+
onion_utils::encrypt_failure_packet(&incoming_packet_shared_secret, &packet)
3802+
}
37873803
},
37883804
HTLCFailReason::LightningError { err } => {
37893805
log_trace!(self.logger, "Failing HTLC with payment_hash {} backwards with pre-built LightningError", log_bytes!(payment_hash.0));
@@ -4487,7 +4503,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
44874503
onion_utils::build_first_hop_failure_packet(incoming_shared_secret, error_code, &{
44884504
let mut res = Vec::with_capacity(8 + 128);
44894505
// TODO: underspecified, follow https://github.com/lightningnetwork/lightning-rfc/issues/791
4490-
res.extend_from_slice(&byte_utils::be16_to_array(0));
4506+
if error_code == 0x1000 | 20 {
4507+
res.extend_from_slice(&byte_utils::be16_to_array(0));
4508+
}
44914509
res.extend_from_slice(&upd.encode_with_len()[..]);
44924510
res
44934511
}[..])
@@ -5978,6 +5996,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting,
59785996
},
59795997
(1, Receive) => {
59805998
(0, payment_data, required),
5999+
(1, phantom_shared_secret, option),
59816000
(2, incoming_cltv_expiry, required),
59826001
},
59836002
(2, ReceiveKeysend) => {
@@ -6069,6 +6088,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCStatus, ;
60696088

60706089
impl_writeable_tlv_based!(HTLCPreviousHopData, {
60716090
(0, short_channel_id, required),
6091+
(1, phantom_shared_secret, option),
60726092
(2, outpoint, required),
60736093
(4, htlc_id, required),
60746094
(6, incoming_packet_shared_secret, required)

lightning/src/ln/msgs.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,10 +1299,6 @@ impl Readable for FinalOnionHopData {
12991299

13001300
impl Writeable for OnionHopData {
13011301
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
1302-
// Note that this should never be reachable if Rust-Lightning generated the message, as we
1303-
// check values are sane long before we get here, though its possible in the future
1304-
// user-generated messages may hit this.
1305-
if self.amt_to_forward > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
13061302
match self.format {
13071303
OnionHopDataFormat::Legacy { short_channel_id } => {
13081304
0u8.write(w)?;
@@ -1319,9 +1315,6 @@ impl Writeable for OnionHopData {
13191315
});
13201316
},
13211317
OnionHopDataFormat::FinalNode { ref payment_data, ref keysend_preimage } => {
1322-
if let Some(final_data) = payment_data {
1323-
if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
1324-
}
13251318
encode_varint_length_prefixed_tlv!(w, {
13261319
(2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required),
13271320
(4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required),

0 commit comments

Comments
 (0)