Skip to content

Commit 6a54618

Browse files
committed
Add OffersContext::InvoiceRequest
To authenticate that an InvoiceRequest is for a valid Offer, include the nonce from the Offer::metadata in the Offer::paths. This can be used to prevent de-anonymization attacks where an attacker sends requests using self-constructed paths to nodes near the Offer::paths' introduction nodes.
1 parent a5145e4 commit 6a54618

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

lightning/src/blinded_path/message.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use crate::io;
2222
use crate::io::Cursor;
2323
use crate::ln::channelmanager::PaymentId;
2424
use crate::ln::onion_utils;
25+
use crate::offers::nonce::Nonce;
2526
use crate::onion_message::packet::ControlTlvs;
2627
use crate::sign::{NodeSigner, Recipient};
2728
use crate::crypto::streams::ChaChaPolyReadAdapter;
@@ -112,6 +113,20 @@ pub enum OffersContext {
112113
/// This variant is used when a message is sent without using a [`BlindedPath`] or over one
113114
/// created prior to LDK version 0.0.124.
114115
Unknown {},
116+
/// Context used by a [`BlindedPath`] within an [`Offer`].
117+
///
118+
/// This variant is intended to be received when handling an [`InvoiceRequest`].
119+
///
120+
/// [`Offer`]: crate::offers::offer::Offer
121+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
122+
InvoiceRequest {
123+
/// A nonce used for authenticating that an [`InvoiceRequest`] is for a valid [`Offer`] and
124+
/// for deriving the offer's signing keys.
125+
///
126+
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
127+
/// [`Offer`]: crate::offers::offer::Offer
128+
nonce: Nonce,
129+
},
115130
/// Context used by a [`BlindedPath`] within a [`Refund`] or as a reply path for an
116131
/// [`InvoiceRequest`].
117132
///
@@ -138,7 +153,10 @@ impl_writeable_tlv_based_enum!(MessageContext,
138153

139154
impl_writeable_tlv_based_enum!(OffersContext,
140155
(0, Unknown) => {},
141-
(1, OutboundPayment) => {
156+
(1, InvoiceRequest) => {
157+
(0, nonce, required),
158+
},
159+
(2, OutboundPayment) => {
142160
(0, payment_id, required),
143161
},
144162
);

lightning/src/ln/channelmanager.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8786,7 +8786,8 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
87868786
let secp_ctx = &$self.secp_ctx;
87878787

87888788
let nonce = Nonce::from_entropy_source(entropy);
8789-
let path = $self.create_blinded_paths_using_absolute_expiry(OffersContext::Unknown {}, absolute_expiry)
8789+
let context = OffersContext::InvoiceRequest { nonce };
8790+
let path = $self.create_blinded_paths_using_absolute_expiry(context, absolute_expiry)
87908791
.and_then(|paths| paths.into_iter().next().ok_or(()))
87918792
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
87928793
let builder = OfferBuilder::deriving_signing_pubkey(node_id, expanded_key, nonce, secp_ctx)

lightning/src/offers/nonce.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99

1010
//! A number used only once.
1111
12+
use crate::io::{self, Read};
13+
use crate::ln::msgs::DecodeError;
1214
use crate::sign::EntropySource;
15+
use crate::util::ser::{Readable, Writeable, Writer};
1316
use core::ops::Deref;
1417

1518
#[allow(unused_imports)]
@@ -62,3 +65,15 @@ impl TryFrom<&[u8]> for Nonce {
6265
Ok(Self(copied_bytes))
6366
}
6467
}
68+
69+
impl Writeable for Nonce {
70+
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
71+
self.0.write(w)
72+
}
73+
}
74+
75+
impl Readable for Nonce {
76+
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
77+
Ok(Nonce(Readable::read(r)?))
78+
}
79+
}

0 commit comments

Comments
 (0)