From bd0dd9b9a8cf21e77ad8aa5209ee3fbd0f43d0ce Mon Sep 17 00:00:00 2001 From: Jeffrey Czyz Date: Sun, 1 Dec 2024 15:48:47 -0500 Subject: [PATCH] HMAC construction/verification for ReceiveTlvs When receiving a PaymentContext from a blinded payment, the context must be authenticated. Otherwise, the context can be forged and would appear within a PaymentPurpose. Add functions for constructing and verifying an HMAC for the ReceiveTlvs, which contains the PaymentContext. --- lightning/src/ln/channelmanager.rs | 14 ++++++++++++++ lightning/src/offers/signer.rs | 23 +++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 53c190d36..bc63ef294 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -480,6 +480,20 @@ impl Verification for PaymentHash { } } +impl Verification for ReceiveTlvs { + fn hmac_for_offer_payment( + &self, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, + ) -> Hmac { + signer::hmac_for_payment_tlvs(self, nonce, expanded_key) + } + + fn verify_for_offer_payment( + &self, hmac: Hmac, nonce: Nonce, expanded_key: &inbound_payment::ExpandedKey, + ) -> Result<(), ()> { + signer::verify_payment_tlvs(self, hmac, nonce, expanded_key) + } +} + /// A user-provided identifier in [`ChannelManager::send_payment`] used to uniquely identify /// a payment and ensure idempotency in LDK. /// diff --git a/lightning/src/offers/signer.rs b/lightning/src/offers/signer.rs index d8caa2175..aee79175f 100644 --- a/lightning/src/offers/signer.rs +++ b/lightning/src/offers/signer.rs @@ -16,6 +16,7 @@ use bitcoin::hashes::sha256::Hash as Sha256; use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey, self}; use types::payment::PaymentHash; use core::fmt; +use crate::blinded_path::payment::ReceiveTlvs; use crate::ln::channelmanager::PaymentId; use crate::ln::inbound_payment::{ExpandedKey, IV_LEN}; use crate::offers::merkle::TlvRecord; @@ -46,6 +47,9 @@ const ASYNC_PAYMENT_ID_HMAC_INPUT: &[u8; 16] = &[6; 16]; // HMAC input for a `PaymentHash`. The HMAC is used in `OffersContext::InboundPayment`. 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]; + /// Message metadata which possibly is derived from [`MetadataMaterial`] such that it can be /// verified. #[derive(Clone)] @@ -459,3 +463,22 @@ fn hmac_for_payment_id( Hmac::from_engine(hmac) } + +pub(crate) fn hmac_for_payment_tlvs( + receive_tlvs: &ReceiveTlvs, nonce: Nonce, expanded_key: &ExpandedKey, +) -> Hmac { + const IV_BYTES: &[u8; IV_LEN] = b"LDK Payment TLVs"; + let mut hmac = expanded_key.hmac_for_offer(); + hmac.input(IV_BYTES); + hmac.input(&nonce.0); + hmac.input(PAYMENT_TLVS_HMAC_INPUT); + receive_tlvs.write(&mut hmac).unwrap(); + + Hmac::from_engine(hmac) +} + +pub(crate) fn verify_payment_tlvs( + receive_tlvs: &ReceiveTlvs, hmac: Hmac, nonce: Nonce, expanded_key: &ExpandedKey, +) -> Result<(), ()> { + if hmac_for_payment_tlvs(receive_tlvs, nonce, expanded_key) == hmac { Ok(()) } else { Err(()) } +}