]> git.bitcoin.ninja Git - rust-lightning/commitdiff
Add nonce to OffersContext::OutboundPayment
authorJeffrey Czyz <jkczyz@gmail.com>
Fri, 12 Jul 2024 21:59:22 +0000 (16:59 -0500)
committerJeffrey Czyz <jkczyz@gmail.com>
Mon, 22 Jul 2024 16:34:04 +0000 (11:34 -0500)
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
lightning/src/ln/channelmanager.rs

index 74d31c5b99efb82d592977670a022177a7243370..04cb867dac1f5e4561b39e3356e3a25cb7322209 100644 (file)
@@ -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),
        },
 );
 
index 1988aba4a262b2c4cb0f927bd6f6f740d87755ab..9aa80348eac1c80f634caee02a84cfda25a6d061 100644 (file)
@@ -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,
                                };