Skip to content

Commit

Permalink
Disallow user-provided payer_signing_pubkey
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jkczyz committed Sep 11, 2024
1 parent e6c0215 commit 14bccfe
Show file tree
Hide file tree
Showing 7 changed files with 633 additions and 660 deletions.
43 changes: 25 additions & 18 deletions fuzz/src/offer_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@
// licenses.

use crate::utils::test_logger;
use bitcoin::secp256k1::{Keypair, PublicKey, Secp256k1, SecretKey};
use bitcoin::secp256k1::Secp256k1;
use core::convert::TryFrom;
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::ln::channelmanager::PaymentId;
use lightning::ln::inbound_payment::ExpandedKey;
use lightning::offers::invoice_request::InvoiceRequest;
use lightning::offers::nonce::Nonce;
use lightning::offers::offer::{Amount, Offer, Quantity};
use lightning::offers::parse::Bolt12SemanticError;
use lightning::sign::{EntropySource, KeyMaterial};
use lightning::util::ser::Writeable;

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

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

if let Ok(invoice_request) = build_response(&offer, pubkey) {
invoice_request
.sign(|message: &UnsignedInvoiceRequest| {
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
})
.unwrap()
.write(&mut buffer)
.unwrap();
if let Ok(invoice_request) = build_request(&offer) {
invoice_request.write(&mut buffer).unwrap();
}
}
}

fn build_response(
offer: &Offer, pubkey: PublicKey,
) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
let mut builder = offer.request_invoice(vec![42; 64], pubkey)?;
struct FixedEntropy;

impl EntropySource for FixedEntropy {
fn get_secure_random_bytes(&self) -> [u8; 32] {
[42; 32]
}
}

fn build_request(offer: &Offer) -> Result<InvoiceRequest, Bolt12SemanticError> {
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
let entropy = FixedEntropy {};
let nonce = Nonce::from_entropy_source(&entropy);
let secp_ctx = Secp256k1::new();
let payment_id = PaymentId([1; 32]);

let mut builder = offer.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id)?;

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

builder.build()
builder.build_and_sign()
}

pub fn offer_deser_test<Out: test_logger::Output>(data: &[u8], out: Out) {
Expand Down
2 changes: 1 addition & 1 deletion lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9066,7 +9066,7 @@ where

let nonce = Nonce::from_entropy_source(entropy);
let builder: InvoiceRequestBuilder<DerivedPayerSigningPubkey, secp256k1::All> = offer
.request_invoice_deriving_signing_pubkey(expanded_key, nonce, secp_ctx, payment_id)?
.request_invoice(expanded_key, nonce, secp_ctx, payment_id)?
.into();
let builder = builder.chain_hash(self.chain_hash)?;

Expand Down
24 changes: 15 additions & 9 deletions lightning/src/ln/outbound_payment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1949,14 +1949,17 @@ mod tests {
use crate::ln::types::PaymentHash;
use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
use crate::ln::features::{Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures};
use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::{ErrorAction, LightningError};
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, Retry, RetryableSendFailure, StaleExpiration};
#[cfg(feature = "std")]
use crate::offers::invoice::DEFAULT_RELATIVE_EXPIRY;
use crate::offers::nonce::Nonce;
use crate::offers::offer::OfferBuilder;
use crate::offers::test_utils::*;
use crate::routing::gossip::NetworkGraph;
use crate::routing::router::{InFlightHtlcs, Path, PaymentParameters, Route, RouteHop, RouteParameters};
use crate::sign::KeyMaterial;
use crate::sync::{Arc, Mutex, RwLock};
use crate::util::errors::APIError;
use crate::util::test_utils;
Expand Down Expand Up @@ -2300,6 +2303,8 @@ mod tests {
let router = test_utils::TestRouter::new(network_graph, &logger, &scorer);
let secp_ctx = Secp256k1::new();
let keys_manager = test_utils::TestKeysInterface::new(&[0; 32], Network::Testnet);
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
let nonce = Nonce([0; 16]);

let pending_events = Mutex::new(VecDeque::new());
let outbound_payments = OutboundPayments::new();
Expand All @@ -2317,9 +2322,8 @@ mod tests {
let invoice = OfferBuilder::new(recipient_pubkey())
.amount_msats(1000)
.build().unwrap()
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap()
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
.build_and_sign().unwrap()
.respond_with_no_std(payment_paths(), payment_hash(), created_at).unwrap()
.build().unwrap()
.sign(recipient_sign).unwrap();
Expand Down Expand Up @@ -2356,15 +2360,16 @@ mod tests {

let pending_events = Mutex::new(VecDeque::new());
let outbound_payments = OutboundPayments::new();
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
let nonce = Nonce([0; 16]);
let payment_id = PaymentId([0; 32]);
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));

let invoice = OfferBuilder::new(recipient_pubkey())
.amount_msats(1000)
.build().unwrap()
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap()
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
.build_and_sign().unwrap()
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build().unwrap()
.sign(recipient_sign).unwrap();
Expand Down Expand Up @@ -2417,15 +2422,16 @@ mod tests {

let pending_events = Mutex::new(VecDeque::new());
let outbound_payments = OutboundPayments::new();
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
let nonce = Nonce([0; 16]);
let payment_id = PaymentId([0; 32]);
let expiration = StaleExpiration::AbsoluteTimeout(Duration::from_secs(100));

let invoice = OfferBuilder::new(recipient_pubkey())
.amount_msats(1000)
.build().unwrap()
.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
.sign(payer_sign).unwrap()
.request_invoice(&expanded_key, nonce, &secp_ctx, payment_id).unwrap()
.build_and_sign().unwrap()
.respond_with_no_std(payment_paths(), payment_hash(), now()).unwrap()
.build().unwrap()
.sign(recipient_sign).unwrap();
Expand Down
Loading

0 comments on commit 14bccfe

Please sign in to comment.