Skip to content

Commit ad39980

Browse files
committed
Disallow user-provided payer_signing_pubkey
When creating an InvoiceRequests, users may choose to either use a transient signing pubkey generated by LDK or provide a static one. Disallow the latter as it allows users to reuse the same pubkey, which results in poor sender privacy.
1 parent 7a89807 commit ad39980

File tree

7 files changed

+633
-660
lines changed

7 files changed

+633
-660
lines changed

fuzz/src/offer_deser.rs

+25-18
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,15 @@
88
// licenses.
99

1010
use crate::utils::test_logger;
11-
use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey};
11+
use bitcoin::secp256k1::Secp256k1;
1212
use core::convert::TryFrom;
13-
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
13+
use lightning::ln::channelmanager::PaymentId;
14+
use lightning::ln::inbound_payment::ExpandedKey;
15+
use lightning::offers::invoice_request::InvoiceRequest;
16+
use lightning::offers::nonce::Nonce;
1417
use lightning::offers::offer::{Amount, Offer, Quantity};
1518
use lightning::offers::parse::Bolt12SemanticError;
19+
use lightning::sign::{EntropySource, KeyMaterial};
1620
use lightning::util::ser::Writeable;
1721

1822
#[inline]
@@ -22,27 +26,30 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
2226
offer.write(&mut bytes).unwrap();
2327
assert_eq!(data, bytes);
2428

25-
let secp_ctx = Secp256k1::new();
26-
let keys = Keypair::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[42; 32]).unwrap());
27-
let pubkey = PublicKey::from(keys);
2829
let mut buffer = Vec::new();
2930

30-
if let Ok(invoice_request) = build_response(&offer, pubkey) {
31-
invoice_request
32-
.sign(|message: &UnsignedInvoiceRequest| {
33-
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
34-
})
35-
.unwrap()
36-
.write(&mut buffer)
37-
.unwrap();
31+
if let Ok(invoice_request) = build_request(&offer) {
32+
invoice_request.write(&mut buffer).unwrap();
3833
}
3934
}
4035
}
4136

42-
fn build_response(
43-
offer: &Offer, pubkey: PublicKey,
44-
) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
45-
let mut builder = offer.request_invoice(vec![42; 64], pubkey)?;
37+
struct FixedEntropy;
38+
39+
impl EntropySource for FixedEntropy {
40+
fn get_secure_random_bytes(&self) -> [u8; 32] {
41+
[42; 32]
42+
}
43+
}
44+
45+
fn build_request(offer: &Offer) -> Result<InvoiceRequest, Bolt12SemanticError> {
46+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
47+
let entropy = FixedEntropy {};
48+
let nonce = Nonce::from_entropy_source(&entropy);
49+
let secp_ctx = Secp256k1::new();
50+
let payment_id = PaymentId([1; 32]);
51+
52+
let mut builder = offer.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)?;
4653

4754
builder = match offer.amount() {
4855
None => builder.amount_msats(1000).unwrap(),
@@ -56,7 +63,7 @@ fn build_response(
5663
Quantity::One => builder,
5764
};
5865

59-
builder.build()
66+
builder.build_and_sign()
6067
}
6168

6269
pub fn offer_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {

lightning/src/ln/channelmanager.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9227,7 +9227,7 @@ where
92279227

92289228
let nonce = Nonce::from_entropy_source(entropy);
92299229
let builder: InvoiceRequestBuilder<DerivedPayerSigningPubkey, secp256k1::All> = offer
9230-
.request_invoice_deriving_signing_pubkey(expanded_key, nonce, secp_ctx, payment_id)?
9230+
.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
92319231
.into();
92329232
let builder = builder.chain_hash(self.chain_hash)?;
92339233

lightning/src/ln/outbound_payment.rs

+15-9
Original file line numberDiff line numberDiff line change
@@ -2205,14 +2205,17 @@ mod tests {
22052205
use crate::ln::types::{PaymentHash, PaymentPreimage};
22062206
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
22072207
use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
2208+
use crate::ln::inbound_payment::ExpandedKey;
22082209
use crate::ln::msgs::{ErrorAction, LightningError};
22092210
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PendingOutboundPayment, Retry, RetryableSendFailure, StaleExpiration};
22102211
#[cfg(feature = "std")]
22112212
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
2213+
use crate::offers::nonce::Nonce;
22122214
use crate::offers::offer::OfferBuilder;
22132215
use crate::offers::test_utils::*;
22142216
use crate::routing::gossip::NetworkGraph;
22152217
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters};
2218+
use crate::sign::KeyMaterial;
22162219
use crate::sync::{Arc, Mutex, RwLock};
22172220
use crate::util::errors::APIError;
22182221
use crate::util::hash_tables::new_hash_map;
@@ -2557,6 +2560,8 @@ mod tests {
25572560
let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
25582561
let secp_ctx = Secp256k1::new();
25592562
let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
2563+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2564+
let nonce = Nonce([0; 16]);
25602565

25612566
let pending_events = Mutex::new(VecDeque::new());
25622567
let outbound_payments = OutboundPayments::new(new_hash_map());
@@ -2574,9 +2579,8 @@ mod tests {
25742579
let invoice = OfferBuilder::new(recipient_pubkey())
25752580
.amount_msats(1000)
25762581
.build().unwrap()
2577-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2578-
.build().unwrap()
2579-
.sign(payer_sign).unwrap()
2582+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2583+
.build_and_sign().unwrap()
25802584
.respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
25812585
.build().unwrap()
25822586
.sign(recipient_sign).unwrap();
@@ -2613,15 +2617,16 @@ mod tests {
26132617

26142618
let pending_events = Mutex::new(VecDeque::new());
26152619
let outbound_payments = OutboundPayments::new(new_hash_map());
2620+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2621+
let nonce = Nonce([0; 16]);
26162622
let payment_id = PaymentId([0; 32]);
26172623
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
26182624

26192625
let invoice = OfferBuilder::new(recipient_pubkey())
26202626
.amount_msats(1000)
26212627
.build().unwrap()
2622-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2623-
.build().unwrap()
2624-
.sign(payer_sign).unwrap()
2628+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2629+
.build_and_sign().unwrap()
26252630
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
26262631
.build().unwrap()
26272632
.sign(recipient_sign).unwrap();
@@ -2674,15 +2679,16 @@ mod tests {
26742679

26752680
let pending_events = Mutex::new(VecDeque::new());
26762681
let outbound_payments = OutboundPayments::new(new_hash_map());
2682+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
2683+
let nonce = Nonce([0; 16]);
26772684
let payment_id = PaymentId([0; 32]);
26782685
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));
26792686

26802687
let invoice = OfferBuilder::new(recipient_pubkey())
26812688
.amount_msats(1000)
26822689
.build().unwrap()
2683-
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
2684-
.build().unwrap()
2685-
.sign(payer_sign).unwrap()
2690+
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
2691+
.build_and_sign().unwrap()
26862692
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
26872693
.build().unwrap()
26882694
.sign(recipient_sign).unwrap();

0 commit comments

Comments
 (0)