Skip to content

Commit 5350bfa

Browse files
committed
Include HMAC and Nonce in payment::ReceiveTlvs
In order to authenticate a PaymentContext, an HMAC and Nonce must be included along with it in payment::ReceiveTlvs. Compute the HMAC when constructing a BlindedPaymentPath and include it in the recipient's BlindedPaymentTlvs. Authentication will be added in an upcoming commit.
1 parent 5f068df commit 5350bfa

File tree

7 files changed

+65
-11
lines changed

7 files changed

+65
-11
lines changed

fuzz/src/invoice_request_deser.rs

+1
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
9999
htlc_minimum_msat: 1,
100100
},
101101
payment_context,
102+
authentication: None,
102103
};
103104
let intermediate_nodes = [PaymentForwardNode {
104105
tlvs: ForwardTlvs {

fuzz/src/refund_deser.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ fn build_response<T: secp256k1::Signing + secp256k1::Verification>(
7676
htlc_minimum_msat: 1,
7777
},
7878
payment_context,
79+
authentication: None,
7980
};
8081
let intermediate_nodes = [PaymentForwardNode {
8182
tlvs: ForwardTlvs {

lightning/src/blinded_path/payment.rs

+14-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
//! Data structures and methods for constructing [`BlindedPaymentPath`]s to send a payment over.
1111
12+
use bitcoin::hashes::hmac::Hmac;
13+
use bitcoin::hashes::sha256::Hash as Sha256;
1214
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1315

1416
use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp};
@@ -22,6 +24,7 @@ use crate::types::features::BlindedHopFeatures;
2224
use crate::ln::msgs::DecodeError;
2325
use crate::ln::onion_utils;
2426
use crate::offers::invoice_request::InvoiceRequestFields;
27+
use crate::offers::nonce::Nonce;
2528
use crate::offers::offer::OfferId;
2629
use crate::routing::gossip::{NodeId, ReadOnlyNetworkGraph};
2730
use crate::sign::{EntropySource, NodeSigner, Recipient};
@@ -260,6 +263,8 @@ pub struct ReceiveTlvs {
260263
pub payment_constraints: PaymentConstraints,
261264
/// Context for the receiver of this payment.
262265
pub payment_context: PaymentContext,
266+
/// An HMAC of `payment_context` along with a nonce used to construct it.
267+
pub authentication: Option<(Hmac<Sha256>, Nonce)>,
263268
}
264269

265270
/// Data to construct a [`BlindedHop`] for sending a payment over.
@@ -404,7 +409,8 @@ impl Writeable for ReceiveTlvs {
404409
encode_tlv_stream!(w, {
405410
(12, self.payment_constraints, required),
406411
(65536, self.payment_secret, required),
407-
(65537, self.payment_context, required)
412+
(65537, self.payment_context, required),
413+
(65539, self.authentication, option),
408414
});
409415
Ok(())
410416
}
@@ -432,6 +438,7 @@ impl Readable for BlindedPaymentTlvs {
432438
(14, features, (option, encoding: (BlindedHopFeatures, WithoutLength))),
433439
(65536, payment_secret, option),
434440
(65537, payment_context, (default_value, PaymentContext::unknown())),
441+
(65539, authentication, option),
435442
});
436443
let _padding: Option<utils::Padding> = _padding;
437444

@@ -452,6 +459,7 @@ impl Readable for BlindedPaymentTlvs {
452459
payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?,
453460
payment_constraints: payment_constraints.0.unwrap(),
454461
payment_context: payment_context.0.unwrap(),
462+
authentication,
455463
}))
456464
}
457465
}
@@ -683,6 +691,7 @@ mod tests {
683691
htlc_minimum_msat: 1,
684692
},
685693
payment_context: PaymentContext::unknown(),
694+
authentication: None,
686695
};
687696
let htlc_maximum_msat = 100_000;
688697
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, 12).unwrap();
@@ -702,6 +711,7 @@ mod tests {
702711
htlc_minimum_msat: 1,
703712
},
704713
payment_context: PaymentContext::unknown(),
714+
authentication: None,
705715
};
706716
let blinded_payinfo = super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap();
707717
assert_eq!(blinded_payinfo.fee_base_msat, 0);
@@ -758,6 +768,7 @@ mod tests {
758768
htlc_minimum_msat: 3,
759769
},
760770
payment_context: PaymentContext::unknown(),
771+
authentication: None,
761772
};
762773
let htlc_maximum_msat = 100_000;
763774
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16).unwrap();
@@ -811,6 +822,7 @@ mod tests {
811822
htlc_minimum_msat: 1,
812823
},
813824
payment_context: PaymentContext::unknown(),
825+
authentication: None,
814826
};
815827
let htlc_minimum_msat = 3798;
816828
assert!(super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_minimum_msat - 1, TEST_FINAL_CLTV as u16).is_err());
@@ -868,6 +880,7 @@ mod tests {
868880
htlc_minimum_msat: 1,
869881
},
870882
payment_context: PaymentContext::unknown(),
883+
authentication: None,
871884
};
872885

873886
let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, 10_000, TEST_FINAL_CLTV as u16).unwrap();

lightning/src/ln/blinded_payment_tests.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
// You may not use this file except in accordance with one or both of these
88
// licenses.
99

10+
use bitcoin::hashes::hmac::Hmac;
1011
use bitcoin::hashes::hex::FromHex;
12+
use bitcoin::hashes::sha256::Hash as Sha256;
1113
use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey, schnorr};
1214
use bitcoin::secp256k1::ecdh::SharedSecret;
1315
use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
@@ -17,16 +19,18 @@ use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsP
1719
use crate::ln::types::ChannelId;
1820
use crate::types::payment::{PaymentHash, PaymentSecret};
1921
use crate::ln::channelmanager;
20-
use crate::ln::channelmanager::{HTLCFailureMsg, PaymentId, RecipientOnionFields};
22+
use crate::ln::channelmanager::{HTLCFailureMsg, PaymentId, RecipientOnionFields, Verification};
2123
use crate::types::features::{BlindedHopFeatures, ChannelFeatures, NodeFeatures};
2224
use crate::ln::functional_test_utils::*;
25+
use crate::ln::inbound_payment::ExpandedKey;
2326
use crate::ln::msgs;
2427
use crate::ln::msgs::{ChannelMessageHandler, UnsignedGossipMessage};
2528
use crate::ln::onion_payment;
2629
use crate::ln::onion_utils;
2730
use crate::ln::onion_utils::INVALID_ONION_BLINDING;
2831
use crate::ln::outbound_payment::{Retry, IDEMPOTENCY_TIMEOUT_TICKS};
2932
use crate::offers::invoice::UnsignedBolt12Invoice;
33+
use crate::offers::nonce::Nonce;
3034
use crate::prelude::*;
3135
use crate::routing::router::{BlindedTail, Path, Payee, PaymentParameters, RouteHop, RouteParameters};
3236
use crate::sign::{KeyMaterial, NodeSigner, Recipient};
@@ -69,15 +73,19 @@ fn blinded_payment_path(
6973
.unwrap_or_else(|| channel_upds[idx - 1].htlc_maximum_msat),
7074
});
7175
}
72-
let payee_tlvs = ReceiveTlvs {
76+
77+
let mut payee_tlvs = ReceiveTlvs {
7378
payment_secret,
7479
payment_constraints: PaymentConstraints {
7580
max_cltv_expiry: u32::max_value(),
7681
htlc_minimum_msat:
7782
intro_node_min_htlc_opt.unwrap_or_else(|| channel_upds.last().unwrap().htlc_minimum_msat),
7883
},
7984
payment_context: PaymentContext::unknown(),
85+
authentication: None,
8086
};
87+
payee_tlvs.authentication = Some(hmac_payee_tlvs(&payee_tlvs, keys_manager));
88+
8189
let mut secp_ctx = Secp256k1::new();
8290
BlindedPaymentPath::new(
8391
&intermediate_nodes[..], *node_ids.last().unwrap(), payee_tlvs,
@@ -86,6 +94,15 @@ fn blinded_payment_path(
8694
).unwrap()
8795
}
8896

97+
fn hmac_payee_tlvs(
98+
payee_tlvs: &ReceiveTlvs, keys_manager: &test_utils::TestKeysInterface,
99+
) -> (Hmac<Sha256>, Nonce) {
100+
let nonce = Nonce([42u8; 16]);
101+
let expanded_key = ExpandedKey::new(&keys_manager.get_inbound_payment_key_material());
102+
let hmac = payee_tlvs.hmac_for_offer_payment(nonce, &expanded_key);
103+
(hmac, nonce)
104+
}
105+
89106
pub fn get_blinded_route_parameters(
90107
amt_msat: u64, payment_secret: PaymentSecret, intro_node_min_htlc: u64, intro_node_max_htlc: u64,
91108
node_ids: Vec<PublicKey>, channel_upds: &[&msgs::UnsignedChannelUpdate],
@@ -116,14 +133,16 @@ fn do_one_hop_blinded_path(success: bool) {
116133

117134
let amt_msat = 5000;
118135
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
119-
let payee_tlvs = ReceiveTlvs {
136+
let mut payee_tlvs = ReceiveTlvs {
120137
payment_secret,
121138
payment_constraints: PaymentConstraints {
122139
max_cltv_expiry: u32::max_value(),
123140
htlc_minimum_msat: chan_upd.htlc_minimum_msat,
124141
},
125142
payment_context: PaymentContext::unknown(),
143+
authentication: None,
126144
};
145+
payee_tlvs.authentication = Some(hmac_payee_tlvs(&payee_tlvs, &chanmon_cfgs[1].keys_manager));
127146
let mut secp_ctx = Secp256k1::new();
128147
let blinded_path = BlindedPaymentPath::new(
129148
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
@@ -160,14 +179,16 @@ fn mpp_to_one_hop_blinded_path() {
160179

161180
let amt_msat = 15_000_000;
162181
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[3], Some(amt_msat), None);
163-
let payee_tlvs = ReceiveTlvs {
182+
let mut payee_tlvs = ReceiveTlvs {
164183
payment_secret,
165184
payment_constraints: PaymentConstraints {
166185
max_cltv_expiry: u32::max_value(),
167186
htlc_minimum_msat: chan_upd_1_3.htlc_minimum_msat,
168187
},
169188
payment_context: PaymentContext::unknown(),
189+
authentication: None,
170190
};
191+
payee_tlvs.authentication = Some(hmac_payee_tlvs(&payee_tlvs, &chanmon_cfgs[3].keys_manager));
171192
let blinded_path = BlindedPaymentPath::new(
172193
&[], nodes[3].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,
173194
&chanmon_cfgs[3].keys_manager, &secp_ctx
@@ -302,7 +323,7 @@ fn do_forward_checks_failure(check: ForwardCheckFail, intro_fails: bool) {
302323
let mut route_params = get_blinded_route_parameters(amt_msat, payment_secret, 1, 1_0000_0000,
303324
nodes.iter().skip(1).map(|n| n.node.get_our_node_id()).collect(),
304325
&[&chan_upd_1_2, &chan_upd_2_3], &chanmon_cfgs[3].keys_manager);
305-
route_params.payment_params.max_path_length = 18;
326+
route_params.payment_params.max_path_length = 17;
306327

307328
let route = get_route(&nodes[0], &route_params).unwrap();
308329
node_cfgs[0].router.expect_find_route(route_params.clone(), Ok(route.clone()));
@@ -1375,14 +1396,16 @@ fn custom_tlvs_to_blinded_path() {
13751396

13761397
let amt_msat = 5000;
13771398
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[1], Some(amt_msat), None);
1378-
let payee_tlvs = ReceiveTlvs {
1399+
let mut payee_tlvs = ReceiveTlvs {
13791400
payment_secret,
13801401
payment_constraints: PaymentConstraints {
13811402
max_cltv_expiry: u32::max_value(),
13821403
htlc_minimum_msat: chan_upd.htlc_minimum_msat,
13831404
},
13841405
payment_context: PaymentContext::unknown(),
1406+
authentication: None,
13851407
};
1408+
payee_tlvs.authentication = Some(hmac_payee_tlvs(&payee_tlvs, &chanmon_cfgs[1].keys_manager));
13861409
let mut secp_ctx = Secp256k1::new();
13871410
let blinded_path = BlindedPaymentPath::new(
13881411
&[], nodes[1].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,

lightning/src/ln/channelmanager.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -10472,20 +10472,28 @@ where
1047210472
fn create_blinded_payment_paths(
1047310473
&self, amount_msats: u64, payment_secret: PaymentSecret, payment_context: PaymentContext
1047410474
) -> Result<Vec<BlindedPaymentPath>, ()> {
10475+
let expanded_key = &self.inbound_payment_key;
10476+
let entropy = &*self.entropy_source;
1047510477
let secp_ctx = &self.secp_ctx;
1047610478

1047710479
let first_hops = self.list_usable_channels();
1047810480
let payee_node_id = self.get_our_node_id();
1047910481
let max_cltv_expiry = self.best_block.read().unwrap().height + CLTV_FAR_FAR_AWAY
1048010482
+ LATENCY_GRACE_PERIOD_BLOCKS;
10481-
let payee_tlvs = ReceiveTlvs {
10483+
10484+
let mut payee_tlvs = ReceiveTlvs {
1048210485
payment_secret,
1048310486
payment_constraints: PaymentConstraints {
1048410487
max_cltv_expiry,
1048510488
htlc_minimum_msat: 1,
1048610489
},
1048710490
payment_context,
10491+
authentication: None,
1048810492
};
10493+
let nonce = Nonce::from_entropy_source(entropy);
10494+
let hmac = payee_tlvs.hmac_for_offer_payment(nonce, expanded_key);
10495+
payee_tlvs.authentication = Some((hmac, nonce));
10496+
1048910497
self.router.create_blinded_payment_paths(
1049010498
payee_node_id, first_hops, payee_tlvs, amount_msats, secp_ctx
1049110499
)

lightning/src/ln/max_payment_path_len_tests.rs

+10-2
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,19 @@ use crate::blinded_path::payment::{BlindedPayInfo, BlindedPaymentPath, PaymentCo
1616
use crate::events::{Event, MessageSendEventsProvider};
1717
use crate::types::payment::PaymentSecret;
1818
use crate::ln::blinded_payment_tests::get_blinded_route_parameters;
19-
use crate::ln::channelmanager::PaymentId;
19+
use crate::ln::channelmanager::{PaymentId, Verification};
2020
use crate::types::features::BlindedHopFeatures;
2121
use crate::ln::functional_test_utils::*;
22+
use crate::ln::inbound_payment::ExpandedKey;
2223
use crate::ln::msgs;
2324
use crate::ln::msgs::OnionMessageHandler;
2425
use crate::ln::onion_utils;
2526
use crate::ln::onion_utils::MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY;
2627
use crate::ln::outbound_payment::{RecipientOnionFields, Retry, RetryableSendFailure};
28+
use crate::offers::nonce::Nonce;
2729
use crate::prelude::*;
2830
use crate::routing::router::{DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, PaymentParameters, RouteParameters};
31+
use crate::sign::NodeSigner;
2932
use crate::util::errors::APIError;
3033
use crate::util::ser::Writeable;
3134
use crate::util::test_utils;
@@ -157,14 +160,19 @@ fn one_hop_blinded_path_with_custom_tlv() {
157160
// Construct the route parameters for sending to nodes[2]'s 1-hop blinded path.
158161
let amt_msat = 100_000;
159162
let (payment_preimage, payment_hash, payment_secret) = get_payment_preimage_hash(&nodes[2], Some(amt_msat), None);
160-
let payee_tlvs = ReceiveTlvs {
163+
let mut payee_tlvs = ReceiveTlvs {
161164
payment_secret,
162165
payment_constraints: PaymentConstraints {
163166
max_cltv_expiry: u32::max_value(),
164167
htlc_minimum_msat: chan_upd_1_2.htlc_minimum_msat,
165168
},
166169
payment_context: PaymentContext::unknown(),
170+
authentication: None,
167171
};
172+
let nonce = Nonce([42u8; 16]);
173+
let expanded_key = ExpandedKey::new(&chanmon_cfgs[2].keys_manager.get_inbound_payment_key_material());
174+
let hmac = payee_tlvs.hmac_for_offer_payment(nonce, &expanded_key);
175+
payee_tlvs.authentication = Some((hmac, nonce));
168176
let mut secp_ctx = Secp256k1::new();
169177
let blinded_path = BlindedPaymentPath::new(
170178
&[], nodes[2].node.get_our_node_id(), payee_tlvs, u64::MAX, TEST_FINAL_CLTV as u16,

lightning/src/ln/msgs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2908,7 +2908,7 @@ impl<NS: Deref> ReadableArgs<(Option<PublicKey>, NS)> for InboundOnionPayload wh
29082908
})
29092909
},
29102910
ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs {
2911-
payment_secret, payment_constraints, payment_context
2911+
payment_secret, payment_constraints, payment_context, authentication: _,
29122912
})} => {
29132913
if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
29142914
Ok(Self::BlindedReceive {

0 commit comments

Comments
 (0)