Add onion message AsyncPaymentsContext for inbound payments

This context is included in static invoice's blinded message paths, provided
back to us in HeldHtlcAvailable onion messages for blinded path authentication.
In future work, we will check if this context is valid and respond with a
ReleaseHeldHtlc message to release the upstream payment if so.

We also add creation methods for the hmac used for authenticating said blinded
path.
This commit is contained in:
Valentine Wallace 2024-10-30 14:20:50 -04:00
parent 84f200f0ca
commit 96db8aa3d2
No known key found for this signature in database
GPG key ID: FD3E106A2CE099B4
3 changed files with 46 additions and 1 deletions

View file

@ -402,6 +402,24 @@ pub enum AsyncPaymentsContext {
/// containing the expected [`PaymentId`].
hmac: Hmac<Sha256>,
},
/// Context contained within the [`BlindedMessagePath`]s we put in static invoices, provided back
/// to us in corresponding [`HeldHtlcAvailable`] messages.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
InboundPayment {
/// A nonce used for authenticating that a [`HeldHtlcAvailable`] message is valid for a
/// preceding static invoice.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
nonce: Nonce,
/// Authentication code for the [`HeldHtlcAvailable`] message.
///
/// Prevents nodes from creating their own blinded path to us, sending a [`HeldHtlcAvailable`]
/// message and trivially getting notified whenever we come online.
///
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
hmac: Hmac<Sha256>,
},
}
impl_writeable_tlv_based_enum!(MessageContext,
@ -433,6 +451,10 @@ impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
(2, nonce, required),
(4, hmac, required),
},
(1, InboundPayment) => {
(0, nonce, required),
(2, hmac, required),
},
);
/// Contains a simple nonce for use in a blinded path's context.

View file

@ -12209,7 +12209,12 @@ where
fn handle_release_held_htlc(&self, _message: ReleaseHeldHtlc, _context: AsyncPaymentsContext) {
#[cfg(async_payments)] {
let AsyncPaymentsContext::OutboundPayment { payment_id, hmac, nonce } = _context;
let (payment_id, nonce, hmac) = match _context {
AsyncPaymentsContext::OutboundPayment { payment_id, hmac, nonce } => {
(payment_id, nonce, hmac)
},
_ => return
};
if payment_id.verify_for_async_payment(hmac, nonce, &self.inbound_payment_key).is_err() { return }
if let Err(e) = self.send_payment_for_static_invoice(payment_id) {
log_trace!(

View file

@ -50,6 +50,11 @@ const PAYMENT_HASH_HMAC_INPUT: &[u8; 16] = &[7; 16];
// HMAC input for `ReceiveTlvs`. The HMAC is used in `blinded_path::payment::PaymentContext`.
const PAYMENT_TLVS_HMAC_INPUT: &[u8; 16] = &[8; 16];
// HMAC input used in `AsyncPaymentsContext::InboundPayment` to authenticate inbound
// held_htlc_available onion messages.
#[cfg(async_payments)]
const ASYNC_PAYMENTS_HELD_HTLC_HMAC_INPUT: &[u8; 16] = &[9; 16];
/// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be
/// verified.
#[derive(Clone)]
@ -483,3 +488,16 @@ pub(crate) fn verify_payment_tlvs(
) -> Result<(), ()> {
if hmac_for_payment_tlvs(receive_tlvs, nonce, expanded_key) == hmac { Ok(()) } else { Err(()) }
}
#[cfg(async_payments)]
pub(crate) fn hmac_for_held_htlc_available_context(
nonce: Nonce, expanded_key: &ExpandedKey,
) -> Hmac<Sha256> {
const IV_BYTES: &[u8; IV_LEN] = b"LDK Held HTLC OM";
let mut hmac = expanded_key.hmac_for_offer();
hmac.input(IV_BYTES);
hmac.input(&nonce.0);
hmac.input(ASYNC_PAYMENTS_HELD_HTLC_HMAC_INPUT);
Hmac::from_engine(hmac)
}