From 14634c6ae12897a39e44ac7760b49130a88bd2c9 Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Fri, 12 Jul 2024 16:59:22 -0500 Subject: [PATCH] Add nonce to OffersContext::OutboundPayment To authenticate that a Bolt12Invoice is for a valid InvoiceRequest or Refund, include the nonce from the payer_metadata in the InvoiceRequest reply path or Refund::paths, respectively. This can be used to prevent de-anonymization attacks where an attacker sends invoices using self-constructed paths to nodes near the blinded paths' introduction nodes. --- lightning/src/blinded_path/message.rs | 11 ++++++++++- lightning/src/ln/channelmanager.rs | 11 ++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lightning/src/blinded_path/message.rs b/lightning/src/blinded_path/message.rs index 74d31c5b9..04cb867da 100644 --- a/lightning/src/blinded_path/message.rs +++ b/lightning/src/blinded_path/message.rs @@ -142,7 +142,15 @@ pub enum OffersContext { /// /// [`Refund`]: crate::offers::refund::Refund /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest - payment_id: PaymentId + payment_id: PaymentId, + + /// A nonce used for authenticating that a [`Bolt12Invoice`] is for a valid [`Refund`] or + /// [`InvoiceRequest`] and for deriving their signing keys. + /// + /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice + /// [`Refund`]: crate::offers::refund::Refund + /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest + nonce: Nonce, }, } @@ -158,6 +166,7 @@ impl_writeable_tlv_based_enum!(OffersContext, }, (2, OutboundPayment) => { (0, payment_id, required), + (1, nonce, required), }, ); diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 1988aba4a..9aa80348e 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -8862,7 +8862,7 @@ macro_rules! create_refund_builder { ($self: ident, $builder: ty) => { let secp_ctx = &$self.secp_ctx; let nonce = Nonce::from_entropy_source(entropy); - let context = OffersContext::OutboundPayment { payment_id }; + let context = OffersContext::OutboundPayment { payment_id, nonce }; let path = $self.create_blinded_paths_using_absolute_expiry(context, Some(absolute_expiry)) .and_then(|paths| paths.into_iter().next().ok_or(())) .map_err(|_| Bolt12SemanticError::MissingPaths)?; @@ -8997,8 +8997,9 @@ where }; let invoice_request = builder.build_and_sign()?; - let context = OffersContext::OutboundPayment { payment_id }; - let reply_paths = self.create_blinded_paths(context).map_err(|_| Bolt12SemanticError::MissingPaths)?; + let context = OffersContext::OutboundPayment { payment_id, nonce }; + let reply_paths = self.create_blinded_paths(context) + .map_err(|_| Bolt12SemanticError::MissingPaths)?; let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self); @@ -10697,7 +10698,7 @@ where let abandon_if_payment = |context| { match context { - OffersContext::OutboundPayment { payment_id } => self.abandon_payment(payment_id), + OffersContext::OutboundPayment { payment_id, .. } => self.abandon_payment(payment_id), _ => {}, } }; @@ -10808,7 +10809,7 @@ where OffersMessage::Invoice(invoice) => { let expected_payment_id = match context { OffersContext::Unknown {} if invoice.is_for_refund_without_paths() => None, - OffersContext::OutboundPayment { payment_id } => Some(payment_id), + OffersContext::OutboundPayment { payment_id, .. } => Some(payment_id), _ => return ResponseInstruction::NoResponse, }; -- 2.39.5