diff --git a/lightning/src/ln/blinded_payment_tests.rs b/lightning/src/ln/blinded_payment_tests.rs index 0662d5f9395..0e0939508c4 100644 --- a/lightning/src/ln/blinded_payment_tests.rs +++ b/lightning/src/ln/blinded_payment_tests.rs @@ -1561,7 +1561,7 @@ fn route_blinding_spec_test_vector() { let bob_node_signer = TestEcdhSigner { node_secret: bob_secret }; // Can't use the public API here as we need to avoid the CLTV delta checks (test vector uses // < MIN_CLTV_EXPIRY_DELTA). - let (bob_peeled_onion, _, next_packet_details_opt) = + let (bob_peeled_onion, next_packet_details_opt) = match onion_payment::decode_incoming_update_add_htlc_onion( &bob_update_add, &bob_node_signer, &logger, &secp_ctx ) { @@ -1571,7 +1571,7 @@ fn route_blinding_spec_test_vector() { let (carol_packet_bytes, carol_hmac) = if let onion_utils::Hop::BlindedForward { next_hop_data: msgs::InboundOnionBlindedForwardPayload { short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override - }, next_hop_hmac, new_packet_bytes + }, next_hop_hmac, new_packet_bytes, .. } = bob_peeled_onion { assert_eq!(short_channel_id, 1729); assert!(next_blinding_override.is_none()); @@ -1595,7 +1595,7 @@ fn route_blinding_spec_test_vector() { carol_onion ); let carol_node_signer = TestEcdhSigner { node_secret: carol_secret }; - let (carol_peeled_onion, _, next_packet_details_opt) = + let (carol_peeled_onion, next_packet_details_opt) = match onion_payment::decode_incoming_update_add_htlc_onion( &carol_update_add, &carol_node_signer, &logger, &secp_ctx ) { @@ -1605,7 +1605,7 @@ fn route_blinding_spec_test_vector() { let (dave_packet_bytes, dave_hmac) = if let onion_utils::Hop::BlindedForward { next_hop_data: msgs::InboundOnionBlindedForwardPayload { short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override - }, next_hop_hmac, new_packet_bytes + }, next_hop_hmac, new_packet_bytes, .. } = carol_peeled_onion { assert_eq!(short_channel_id, 1105); assert_eq!(next_blinding_override, Some(pubkey_from_hex("031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"))); @@ -1629,7 +1629,7 @@ fn route_blinding_spec_test_vector() { dave_onion ); let dave_node_signer = TestEcdhSigner { node_secret: dave_secret }; - let (dave_peeled_onion, _, next_packet_details_opt) = + let (dave_peeled_onion, next_packet_details_opt) = match onion_payment::decode_incoming_update_add_htlc_onion( &dave_update_add, &dave_node_signer, &logger, &secp_ctx ) { @@ -1639,7 +1639,7 @@ fn route_blinding_spec_test_vector() { let (eve_packet_bytes, eve_hmac) = if let onion_utils::Hop::BlindedForward { next_hop_data: msgs::InboundOnionBlindedForwardPayload { short_channel_id, payment_relay, payment_constraints, features, intro_node_blinding_point, next_blinding_override - }, next_hop_hmac, new_packet_bytes + }, next_hop_hmac, new_packet_bytes, .. } = dave_peeled_onion { assert_eq!(short_channel_id, 561); assert!(next_blinding_override.is_none()); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index e495aeb67ac..a7902dbdafd 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -4436,27 +4436,16 @@ where } } match decoded_hop { - onion_utils::Hop::Receive(next_hop_data) => { - // OUR PAYMENT! - let current_height: u32 = self.best_block.read().unwrap().height; - match create_recv_pending_htlc_info(msgs::InboundOnionPayload::Receive(next_hop_data), shared_secret, msg.payment_hash, - msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat, - current_height) - { - Ok(info) => { - // Note that we could obviously respond immediately with an update_fulfill_htlc - // message, however that would leak that we are the recipient of this payment, so - // instead we stay symmetric with the forwarding case, only responding (after a - // delay) once they've send us a commitment_signed! - PendingHTLCStatus::Forward(info) - }, - Err(InboundHTLCErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data) - } - }, - onion_utils::Hop::BlindedReceive(next_hop_data) => { + onion_utils::Hop::Receive { .. } | onion_utils::Hop::BlindedReceive { .. } => { + let inbound_onion_payload = match decoded_hop { + onion_utils::Hop::Receive { hop_data, .. } => msgs::InboundOnionPayload::Receive(hop_data), + onion_utils::Hop::BlindedReceive { hop_data, .. } => msgs::InboundOnionPayload::BlindedReceive(hop_data), + _ => unreachable!() + }; + // OUR PAYMENT! let current_height: u32 = self.best_block.read().unwrap().height; - match create_recv_pending_htlc_info(msgs::InboundOnionPayload::BlindedReceive(next_hop_data), shared_secret, msg.payment_hash, + match create_recv_pending_htlc_info(inbound_onion_payload, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, None, allow_underpay, msg.skimmed_fee_msat, current_height) { @@ -4470,14 +4459,14 @@ where Err(InboundHTLCErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data) } }, - onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => { + onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes, .. } => { match create_fwd_pending_htlc_info(msg, msgs::InboundOnionPayload::Forward(next_hop_data), next_hop_hmac, new_packet_bytes, shared_secret, next_packet_pubkey_opt) { Ok(info) => PendingHTLCStatus::Forward(info), Err(InboundHTLCErr { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data) } }, - onion_utils::Hop::BlindedForward { next_hop_data, next_hop_hmac, new_packet_bytes } => { + onion_utils::Hop::BlindedForward { next_hop_data, next_hop_hmac, new_packet_bytes, .. } => { match create_fwd_pending_htlc_info(msg, msgs::InboundOnionPayload::BlindedForward(next_hop_data), next_hop_hmac, new_packet_bytes, shared_secret, next_packet_pubkey_opt) { Ok(info) => PendingHTLCStatus::Forward(info), @@ -5705,7 +5694,7 @@ where let mut htlc_forwards = Vec::new(); let mut htlc_fails = Vec::new(); for update_add_htlc in &update_add_htlcs { - let (next_hop, shared_secret, next_packet_details_opt) = match decode_incoming_update_add_htlc_onion( + let (next_hop, next_packet_details_opt) = match decode_incoming_update_add_htlc_onion( &update_add_htlc, &*self.node_signer, &*self.logger, &self.secp_ctx ) { Ok(decoded_onion) => decoded_onion, @@ -5717,6 +5706,7 @@ where let is_intro_node_blinded_forward = next_hop.is_intro_node_blinded_forward(); let outgoing_scid_opt = next_packet_details_opt.as_ref().map(|d| d.outgoing_scid); + let shared_secret = next_hop.shared_secret().secret_bytes(); // Process the HTLC on the incoming channel. match self.do_funded_channel_callback(incoming_scid, |chan: &mut FundedChannel| { @@ -5875,10 +5865,9 @@ where if let PendingHTLCRouting::Forward { ref onion_packet, .. } = routing { let phantom_pubkey_res = self.node_signer.get_node_id(Recipient::PhantomNode); if phantom_pubkey_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id, &self.chain_hash) { - let phantom_shared_secret = self.node_signer.ecdh(Recipient::PhantomNode, &onion_packet.public_key.unwrap(), None).unwrap().secret_bytes(); let next_hop = match onion_utils::decode_next_payment_hop( - phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, - payment_hash, None, &*self.node_signer + Recipient::PhantomNode, &onion_packet.public_key.unwrap(), &onion_packet.hop_data, + onion_packet.hmac, payment_hash, None, &*self.node_signer ) { Ok(res) => res, Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => { @@ -5889,15 +5878,17 @@ where // of the onion. failed_payment!(err_msg, err_code, sha256_of_onion.to_vec(), None); }, - Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => { + Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code, shared_secret }) => { + let phantom_shared_secret = shared_secret.secret_bytes(); failed_payment!(err_msg, err_code, Vec::new(), Some(phantom_shared_secret)); }, }; - let inbound_onion_payload = match next_hop { - onion_utils::Hop::Receive(hop_data) => msgs::InboundOnionPayload::Receive(hop_data), - onion_utils::Hop::BlindedReceive(hop_data) => msgs::InboundOnionPayload::BlindedReceive(hop_data), + let (inbound_onion_payload, shared_secret) = match next_hop { + onion_utils::Hop::Receive { hop_data, shared_secret } => (msgs::InboundOnionPayload::Receive(hop_data), shared_secret), + onion_utils::Hop::BlindedReceive { hop_data, shared_secret } => (msgs::InboundOnionPayload::BlindedReceive(hop_data), shared_secret), _ => panic!() }; + let phantom_shared_secret = shared_secret.secret_bytes(); let current_height: u32 = self.best_block.read().unwrap().height; match create_recv_pending_htlc_info(inbound_onion_payload, incoming_shared_secret, payment_hash, outgoing_amt_msat, diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index e3505e536de..bccd994bbff 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -3,10 +3,9 @@ //! Primarily features [`peel_payment_onion`], which allows the decoding of an onion statelessly //! and can be used to predict whether we'd accept a payment. -use bitcoin::hashes::{Hash, HashEngine}; -use bitcoin::hashes::hmac::{Hmac, HmacEngine}; +use bitcoin::hashes::Hash; use bitcoin::hashes::sha256::Hash as Sha256; -use bitcoin::secp256k1::{self, PublicKey, Scalar, Secp256k1}; +use bitcoin::secp256k1::{self, PublicKey, Secp256k1}; use crate::blinded_path; use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay}; @@ -285,7 +284,7 @@ where NS::Target: NodeSigner, L::Target: Logger, { - let (hop, shared_secret, next_packet_details_opt) = + let (hop, next_packet_details_opt) = decode_incoming_update_add_htlc_onion(msg, node_signer, logger, secp_ctx ).map_err(|e| { let (err_code, err_data) = match e { @@ -296,7 +295,8 @@ where InboundHTLCErr { msg, err_code, err_data } })?; Ok(match hop { - onion_utils::Hop::Forward { next_hop_hmac, new_packet_bytes, .. } | onion_utils::Hop::BlindedForward { next_hop_hmac, new_packet_bytes, .. } => { + onion_utils::Hop::Forward { shared_secret, next_hop_hmac, new_packet_bytes, .. } | + onion_utils::Hop::BlindedForward { shared_secret, next_hop_hmac, new_packet_bytes, .. } => { let inbound_onion_payload = match hop { onion_utils::Hop::Forward { next_hop_data, .. } => msgs::InboundOnionPayload::Forward(next_hop_data), onion_utils::Hop::BlindedForward { next_hop_data, .. } => msgs::InboundOnionPayload::BlindedForward(next_hop_data), @@ -328,19 +328,19 @@ where // TODO: If this is potentially a phantom payment we should decode the phantom payment // onion here and check it. create_fwd_pending_htlc_info( - msg, inbound_onion_payload, next_hop_hmac, new_packet_bytes, shared_secret, + msg, inbound_onion_payload, next_hop_hmac, new_packet_bytes, shared_secret.secret_bytes(), Some(next_packet_pubkey), )? }, - onion_utils::Hop::Receive(received_data) => { + onion_utils::Hop::Receive { hop_data, shared_secret } => { create_recv_pending_htlc_info( - msgs::InboundOnionPayload::Receive(received_data), shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, + msgs::InboundOnionPayload::Receive(hop_data), shared_secret.secret_bytes(), msg.payment_hash, msg.amount_msat, msg.cltv_expiry, None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height, )? }, - onion_utils::Hop::BlindedReceive(received_data) => { + onion_utils::Hop::BlindedReceive { hop_data, shared_secret } => { create_recv_pending_htlc_info( - msgs::InboundOnionPayload::BlindedReceive(received_data), shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry, + msgs::InboundOnionPayload::BlindedReceive(hop_data), shared_secret.secret_bytes(), msg.payment_hash, msg.amount_msat, msg.cltv_expiry, None, allow_skimmed_fees, msg.skimmed_fee_msat, cur_height, )? } @@ -356,7 +356,7 @@ pub(super) struct NextPacketDetails { pub(super) fn decode_incoming_update_add_htlc_onion( msg: &msgs::UpdateAddHTLC, node_signer: NS, logger: L, secp_ctx: &Secp256k1, -) -> Result<(onion_utils::Hop, [u8; 32], Option), HTLCFailureMsg> +) -> Result<(onion_utils::Hop, Option), HTLCFailureMsg> where NS::Target: NodeSigner, L::Target: Logger, @@ -384,16 +384,6 @@ where return_malformed_err!("invalid ephemeral pubkey", 0x8000 | 0x4000 | 6); } - let blinded_node_id_tweak = msg.blinding_point.map(|bp| { - let blinded_tlvs_ss = node_signer.ecdh(Recipient::Node, &bp, None).unwrap().secret_bytes(); - let mut hmac = HmacEngine::::new(b"blinded_node_id"); - hmac.input(blinded_tlvs_ss.as_ref()); - Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap() - }); - let shared_secret = node_signer.ecdh( - Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), blinded_node_id_tweak.as_ref() - ).unwrap().secret_bytes(); - if msg.onion_routing_packet.version != 0 { //TODO: Spec doesn't indicate if we should only hash hop_data here (and in other //sha256_of_onion error data packets), or the entire onion_routing_packet. Either way, @@ -403,58 +393,55 @@ where //node knows the HMAC matched, so they already know what is there... return_malformed_err!("Unknown onion packet version", 0x8000 | 0x4000 | 4); } - macro_rules! return_err { - ($msg: expr, $err_code: expr, $data: expr) => { - { - if msg.blinding_point.is_some() { - return_malformed_err!($msg, INVALID_ONION_BLINDING) - } - log_info!(logger, "Failed to accept/forward incoming HTLC: {}", $msg); - return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC { - channel_id: msg.channel_id, - htlc_id: msg.htlc_id, - reason: HTLCFailReason::reason($err_code, $data.to_vec()) - .get_encrypted_failure_packet(&shared_secret, &None), - })); - } + let encode_relay_error = |message: &str, err_code: u16, shared_secret: [u8; 32], data: &[u8]| { + if msg.blinding_point.is_some() { + return_malformed_err!(message, INVALID_ONION_BLINDING) } - } + + log_info!(logger, "Failed to accept/forward incoming HTLC: {}", message); + return Err(HTLCFailureMsg::Relay(msgs::UpdateFailHTLC { + channel_id: msg.channel_id, + htlc_id: msg.htlc_id, + reason: HTLCFailReason::reason(err_code, data.to_vec()) + .get_encrypted_failure_packet(&shared_secret, &None), + })); + }; let next_hop = match onion_utils::decode_next_payment_hop( - shared_secret, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, + Recipient::Node, &msg.onion_routing_packet.public_key.unwrap(), &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac, msg.payment_hash, msg.blinding_point, node_signer ) { Ok(res) => res, Err(onion_utils::OnionDecodeErr::Malformed { err_msg, err_code }) => { return_malformed_err!(err_msg, err_code); }, - Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code }) => { - return_err!(err_msg, err_code, &[0; 0]); + Err(onion_utils::OnionDecodeErr::Relay { err_msg, err_code, shared_secret }) => { + return encode_relay_error(err_msg, err_code, shared_secret.secret_bytes(), &[0; 0]); }, }; let next_packet_details = match next_hop { - Hop::Forward { next_hop_data: msgs::InboundOnionForwardPayload { short_channel_id, amt_to_forward, outgoing_cltv_value }, .. } => { + Hop::Forward { next_hop_data: msgs::InboundOnionForwardPayload { short_channel_id, amt_to_forward, outgoing_cltv_value }, shared_secret, .. } => { let next_packet_pubkey = onion_utils::next_hop_pubkey(secp_ctx, - msg.onion_routing_packet.public_key.unwrap(), &shared_secret); + msg.onion_routing_packet.public_key.unwrap(), &shared_secret.secret_bytes()); Some(NextPacketDetails { next_packet_pubkey, outgoing_scid: short_channel_id, outgoing_amt_msat: amt_to_forward, outgoing_cltv_value }) } - Hop::BlindedForward { next_hop_data: msgs::InboundOnionBlindedForwardPayload { short_channel_id, ref payment_relay, ref payment_constraints, ref features, .. }, .. } => { + Hop::BlindedForward { next_hop_data: msgs::InboundOnionBlindedForwardPayload { short_channel_id, ref payment_relay, ref payment_constraints, ref features, .. }, shared_secret, .. } => { let (amt_to_forward, outgoing_cltv_value) = match check_blinded_forward( msg.amount_msat, msg.cltv_expiry, &payment_relay, &payment_constraints, &features ) { Ok((amt, cltv)) => (amt, cltv), Err(()) => { - return_err!("Underflow calculating outbound amount or cltv value for blinded forward", - INVALID_ONION_BLINDING, &[0; 32]); + return encode_relay_error("Underflow calculating outbound amount or cltv value for blinded forward", + INVALID_ONION_BLINDING, shared_secret.secret_bytes(), &[0; 32]); } }; let next_packet_pubkey = onion_utils::next_hop_pubkey(&secp_ctx, - msg.onion_routing_packet.public_key.unwrap(), &shared_secret); + msg.onion_routing_packet.public_key.unwrap(), &shared_secret.secret_bytes()); Some(NextPacketDetails { next_packet_pubkey, outgoing_scid: short_channel_id, outgoing_amt_msat: amt_to_forward, outgoing_cltv_value @@ -463,7 +450,7 @@ where _ => None }; - Ok((next_hop, shared_secret, next_packet_details)) + Ok((next_hop, next_packet_details)) } pub(super) fn check_incoming_htlc_cltv( diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 35de2403441..a76cd5caa4b 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -16,7 +16,7 @@ use crate::ln::msgs; use crate::offers::invoice_request::InvoiceRequest; use crate::routing::gossip::NetworkUpdate; use crate::routing::router::{BlindedTail, Path, RouteHop, RouteParameters, TrampolineHop}; -use crate::sign::NodeSigner; +use crate::sign::{NodeSigner, Recipient}; use crate::types::features::{ChannelFeatures, NodeFeatures}; use crate::types::payment::{PaymentHash, PaymentPreimage}; use crate::util::errors::{self, APIError}; @@ -1419,6 +1419,8 @@ pub(crate) enum Hop { Forward { /// Onion payload data used in forwarding the payment. next_hop_data: msgs::InboundOnionForwardPayload, + /// Shared secret that was used to decrypt next_hop_data. + shared_secret: SharedSecret, /// HMAC of the next hop's onion packet. next_hop_hmac: [u8; 32], /// Bytes of the onion packet we're forwarding. @@ -1428,6 +1430,8 @@ pub(crate) enum Hop { BlindedForward { /// Onion payload data used in forwarding the payment. next_hop_data: msgs::InboundOnionBlindedForwardPayload, + /// Shared secret that was used to decrypt next_hop_data. + shared_secret: SharedSecret, /// HMAC of the next hop's onion packet. next_hop_hmac: [u8; 32], /// Bytes of the onion packet we're forwarding. @@ -1435,10 +1439,20 @@ pub(crate) enum Hop { }, /// This onion payload was for us, not for forwarding to a next-hop. Contains information for /// verifying the incoming payment. - Receive(msgs::InboundOnionReceivePayload), + Receive { + /// Onion payload data used to receive our payment. + hop_data: msgs::InboundOnionReceivePayload, + /// Shared secret that was used to decrypt hop_data. + shared_secret: SharedSecret, + }, /// This onion payload was for us, not for forwarding to a next-hop. Contains information for /// verifying the incoming payment. - BlindedReceive(msgs::InboundOnionBlindedReceivePayload), + BlindedReceive { + /// Onion payload data used to receive our payment. + hop_data: msgs::InboundOnionBlindedReceivePayload, + /// Shared secret that was used to decrypt hop_data. + shared_secret: SharedSecret, + }, } impl Hop { @@ -1454,6 +1468,15 @@ impl Hop { _ => false, } } + + pub(crate) fn shared_secret(&self) -> &SharedSecret { + match self { + Hop::Forward { shared_secret, .. } => shared_secret, + Hop::BlindedForward { shared_secret, .. } => shared_secret, + Hop::Receive { shared_secret, .. } => shared_secret, + Hop::BlindedReceive { shared_secret, .. } => shared_secret, + } + } } /// Error returned when we fail to decode the onion packet. @@ -1462,18 +1485,27 @@ pub(crate) enum OnionDecodeErr { /// The HMAC of the onion packet did not match the hop data. Malformed { err_msg: &'static str, err_code: u16 }, /// We failed to decode the onion payload. - Relay { err_msg: &'static str, err_code: u16 }, + Relay { err_msg: &'static str, err_code: u16, shared_secret: SharedSecret }, } pub(crate) fn decode_next_payment_hop( - shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32], payment_hash: PaymentHash, - blinding_point: Option, node_signer: NS, + recipient: Recipient, hop_pubkey: &PublicKey, hop_data: &[u8], hmac_bytes: [u8; 32], + payment_hash: PaymentHash, blinding_point: Option, node_signer: NS, ) -> Result where NS::Target: NodeSigner, { + let blinded_node_id_tweak = blinding_point.map(|bp| { + let blinded_tlvs_ss = node_signer.ecdh(recipient, &bp, None).unwrap().secret_bytes(); + let mut hmac = HmacEngine::::new(b"blinded_node_id"); + hmac.input(blinded_tlvs_ss.as_ref()); + Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap() + }); + let shared_secret = + node_signer.ecdh(recipient, hop_pubkey, blinded_node_id_tweak.as_ref()).unwrap(); + let decoded_hop: Result<(msgs::InboundOnionPayload, Option<_>), _> = decode_next_hop( - shared_secret, + shared_secret.secret_bytes(), hop_data, hmac_bytes, Some(payment_hash), @@ -1482,25 +1514,56 @@ where match decoded_hop { Ok((next_hop_data, Some((next_hop_hmac, FixedSizeOnionPacket(new_packet_bytes))))) => { match next_hop_data { - msgs::InboundOnionPayload::Forward(next_hop_data) => { - Ok(Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes }) - }, + msgs::InboundOnionPayload::Forward(next_hop_data) => Ok(Hop::Forward { + shared_secret, + next_hop_data, + next_hop_hmac, + new_packet_bytes, + }), msgs::InboundOnionPayload::BlindedForward(next_hop_data) => { - Ok(Hop::BlindedForward { next_hop_data, next_hop_hmac, new_packet_bytes }) + Ok(Hop::BlindedForward { + shared_secret, + next_hop_data, + next_hop_hmac, + new_packet_bytes, + }) + }, + _ => { + if blinding_point.is_some() { + return Err(OnionDecodeErr::Malformed { + err_msg: + "Final Node OnionHopData provided for us as an intermediary node", + err_code: INVALID_ONION_BLINDING, + }); + } + Err(OnionDecodeErr::Relay { + err_msg: "Final Node OnionHopData provided for us as an intermediary node", + err_code: 0x4000 | 22, + shared_secret, + }) }, - _ => Err(OnionDecodeErr::Relay { - err_msg: "Final Node OnionHopData provided for us as an intermediary node", - err_code: 0x4000 | 22, - }), } }, Ok((next_hop_data, None)) => match next_hop_data { - msgs::InboundOnionPayload::Receive(payload) => Ok(Hop::Receive(payload)), - msgs::InboundOnionPayload::BlindedReceive(payload) => Ok(Hop::BlindedReceive(payload)), - _ => Err(OnionDecodeErr::Relay { - err_msg: "Intermediate Node OnionHopData provided for us as a final node", - err_code: 0x4000 | 22, - }), + msgs::InboundOnionPayload::Receive(hop_data) => { + Ok(Hop::Receive { shared_secret, hop_data }) + }, + msgs::InboundOnionPayload::BlindedReceive(hop_data) => { + Ok(Hop::BlindedReceive { shared_secret, hop_data }) + }, + _ => { + if blinding_point.is_some() { + return Err(OnionDecodeErr::Malformed { + err_msg: "Intermediate Node OnionHopData provided for us as a final node", + err_code: INVALID_ONION_BLINDING, + }); + } + Err(OnionDecodeErr::Relay { + err_msg: "Intermediate Node OnionHopData provided for us as a final node", + err_code: 0x4000 | 22, + shared_secret, + }) + }, }, Err(e) => Err(e), } @@ -1646,6 +1709,7 @@ fn decode_next_hop, N: NextPacketBytes>( return Err(OnionDecodeErr::Relay { err_msg: "Unable to decode our hop data", err_code: error_code, + shared_secret: SharedSecret::from_bytes(shared_secret), }); }, Ok(msg) => { @@ -1654,6 +1718,7 @@ fn decode_next_hop, N: NextPacketBytes>( return Err(OnionDecodeErr::Relay { err_msg: "Unable to decode our hop data", err_code: 0x4000 | 22, + shared_secret: SharedSecret::from_bytes(shared_secret), }); } if hmac == [0; 32] { diff --git a/lightning/src/sign/mod.rs b/lightning/src/sign/mod.rs index 7aa41531ce2..3ba950f548d 100644 --- a/lightning/src/sign/mod.rs +++ b/lightning/src/sign/mod.rs @@ -822,6 +822,7 @@ pub trait ChannelSigner { /// /// This indicates to [`NodeSigner::sign_invoice`] what node secret key should be used to sign /// the invoice. +#[derive(Clone, Copy)] pub enum Recipient { /// The invoice should be signed with the local node secret key. Node,