X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fchannelmanager.rs;h=2c99c821468e299b3ad2c6c34f34991d36204aaa;hb=70f7db981099ef3a7aad14ca1987106b2f07c014;hp=4e493546c23e7be9ddc9a31414e137c14c27be5e;hpb=f254bb49acab6c1ca15fac4368cac1e8edb3d92f;p=rust-lightning diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 4e493546..2c99c821 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -48,7 +48,7 @@ use ln::msgs; use ln::msgs::NetAddress; use ln::onion_utils; use ln::msgs::{ChannelMessageHandler, DecodeError, LightningError, MAX_VALUE_MSAT, OptionalField}; -use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner}; +use chain::keysinterface::{Sign, KeysInterface, KeysManager, InMemorySigner, Recipient}; use util::config::UserConfig; use util::events::{EventHandler, EventsProvider, MessageSendEvent, MessageSendEventsProvider, ClosureReason}; use util::{byte_utils, events}; @@ -81,6 +81,7 @@ mod inbound_payment { use ln::msgs; use ln::msgs::MAX_VALUE_MSAT; use util::chacha20::ChaCha20; + use util::crypto::hkdf_extract_expand_thrice; use util::logger::Logger; use core::convert::TryInto; @@ -112,7 +113,13 @@ mod inbound_payment { impl ExpandedKey { pub(super) fn new(key_material: &KeyMaterial) -> ExpandedKey { - hkdf_extract_expand(b"LDK Inbound Payment Key Expansion", &key_material) + let (metadata_key, ldk_pmt_hash_key, user_pmt_hash_key) = + hkdf_extract_expand_thrice(b"LDK Inbound Payment Key Expansion", &key_material.0); + Self { + metadata_key, + ldk_pmt_hash_key, + user_pmt_hash_key, + } } } @@ -330,31 +337,6 @@ mod inbound_payment { } return Ok(PaymentPreimage(decoded_payment_preimage)) } - - fn hkdf_extract_expand(salt: &[u8], ikm: &KeyMaterial) -> ExpandedKey { - let mut hmac = HmacEngine::::new(salt); - hmac.input(&ikm.0); - let prk = Hmac::from_engine(hmac).into_inner(); - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&[1; 1]); - let metadata_key = Hmac::from_engine(hmac).into_inner(); - - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&metadata_key); - hmac.input(&[2; 1]); - let ldk_pmt_hash_key = Hmac::from_engine(hmac).into_inner(); - - let mut hmac = HmacEngine::::new(&prk[..]); - hmac.input(&ldk_pmt_hash_key); - hmac.input(&[3; 1]); - let user_pmt_hash_key = Hmac::from_engine(hmac).into_inner(); - - ExpandedKey { - metadata_key, - ldk_pmt_hash_key, - user_pmt_hash_key, - } - } } // We hold various information about HTLC relay in the HTLC objects in Channel itself: @@ -536,6 +518,12 @@ pub(super) enum HTLCFailReason { } } +struct ReceiveError { + err_code: u16, + err_data: Vec, + msg: &'static str, +} + /// Return value for claim_funds_from_hop enum ClaimFundsFromHop { PrevHopForceClosed, @@ -1697,8 +1685,8 @@ impl ChannelMana pending_inbound_payments: Mutex::new(HashMap::new()), pending_outbound_payments: Mutex::new(HashMap::new()), - our_network_key: keys_manager.get_node_secret(), - our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret()), + our_network_key: keys_manager.get_node_secret(Recipient::Node).unwrap(), + our_network_pubkey: PublicKey::from_secret_key(&secp_ctx, &keys_manager.get_node_secret(Recipient::Node).unwrap()), secp_ctx, inbound_payment_key: expanded_inbound_key, @@ -2061,6 +2049,102 @@ impl ChannelMana } } + fn construct_recv_pending_htlc_info(&self, hop_data: msgs::OnionHopData, shared_secret: [u8; 32], + payment_hash: PaymentHash, amt_msat: u64, cltv_expiry: u32) -> Result + { + // final_incorrect_cltv_expiry + if hop_data.outgoing_cltv_value != cltv_expiry { + return Err(ReceiveError { + msg: "Upstream node set CLTV to the wrong value", + err_code: 18, + err_data: byte_utils::be32_to_array(cltv_expiry).to_vec() + }) + } + // final_expiry_too_soon + // We have to have some headroom to broadcast on chain if we have the preimage, so make sure + // we have at least HTLC_FAIL_BACK_BUFFER blocks to go. + // Also, ensure that, in the case of an unknown preimage for the received payment hash, our + // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a + // channel closure (see HTLC_FAIL_BACK_BUFFER rationale). + if (hop_data.outgoing_cltv_value as u64) <= self.best_block.read().unwrap().height() as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 { + return Err(ReceiveError { + err_code: 17, + err_data: Vec::new(), + msg: "The final CLTV expiry is too soon to handle", + }); + } + if hop_data.amt_to_forward > amt_msat { + return Err(ReceiveError { + err_code: 19, + err_data: byte_utils::be64_to_array(amt_msat).to_vec(), + msg: "Upstream node sent less than we were supposed to receive in payment", + }); + } + + let routing = match hop_data.format { + msgs::OnionHopDataFormat::Legacy { .. } => { + return Err(ReceiveError { + err_code: 0x4000|0x2000|3, + err_data: Vec::new(), + msg: "We require payment_secrets", + }); + }, + msgs::OnionHopDataFormat::NonFinalNode { .. } => { + return Err(ReceiveError { + err_code: 0x4000|22, + err_data: Vec::new(), + msg: "Got non final data with an HMAC of 0", + }); + }, + msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage } => { + if payment_data.is_some() && keysend_preimage.is_some() { + return Err(ReceiveError { + err_code: 0x4000|22, + err_data: Vec::new(), + msg: "We don't support MPP keysend payments", + }); + } else if let Some(data) = payment_data { + PendingHTLCRouting::Receive { + payment_data: data, + incoming_cltv_expiry: hop_data.outgoing_cltv_value, + } + } else if let Some(payment_preimage) = keysend_preimage { + // We need to check that the sender knows the keysend preimage before processing this + // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X + // could discover the final destination of X, by probing the adjacent nodes on the route + // with a keysend payment of identical payment hash to X and observing the processing + // time discrepancies due to a hash collision with X. + let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); + if hashed_preimage != payment_hash { + return Err(ReceiveError { + err_code: 0x4000|22, + err_data: Vec::new(), + msg: "Payment preimage didn't match payment hash", + }); + } + + PendingHTLCRouting::ReceiveKeysend { + payment_preimage, + incoming_cltv_expiry: hop_data.outgoing_cltv_value, + } + } else { + return Err(ReceiveError { + err_code: 0x4000|0x2000|3, + err_data: Vec::new(), + msg: "We require payment_secrets", + }); + } + }, + }; + Ok(PendingHTLCInfo { + routing, + payment_hash, + incoming_shared_secret: shared_secret, + amt_to_forward: amt_msat, + outgoing_cltv_value: hop_data.outgoing_cltv_value, + }) + } + fn decode_update_add_htlc_onion(&self, msg: &msgs::UpdateAddHTLC) -> (PendingHTLCStatus, MutexGuard>) { macro_rules! return_malformed_err { ($msg: expr, $err_code: expr) => { @@ -2126,68 +2210,16 @@ impl ChannelMana let pending_forward_info = match next_hop { onion_utils::Hop::Receive(next_hop_data) => { // OUR PAYMENT! - // final_expiry_too_soon - // We have to have some headroom to broadcast on chain if we have the preimage, so make sure - // we have at least HTLC_FAIL_BACK_BUFFER blocks to go. - // Also, ensure that, in the case of an unknown preimage for the received payment hash, our - // payment logic has enough time to fail the HTLC backward before our onchain logic triggers a - // channel closure (see HTLC_FAIL_BACK_BUFFER rationale). - if (msg.cltv_expiry as u64) <= self.best_block.read().unwrap().height() as u64 + HTLC_FAIL_BACK_BUFFER as u64 + 1 { - return_err!("The final CLTV expiry is too soon to handle", 17, &[0;0]); - } - // final_incorrect_htlc_amount - if next_hop_data.amt_to_forward > msg.amount_msat { - return_err!("Upstream node sent less than we were supposed to receive in payment", 19, &byte_utils::be64_to_array(msg.amount_msat)); - } - // final_incorrect_cltv_expiry - if next_hop_data.outgoing_cltv_value != msg.cltv_expiry { - return_err!("Upstream node set CLTV to the wrong value", 18, &byte_utils::be32_to_array(msg.cltv_expiry)); - } - - let routing = match next_hop_data.format { - msgs::OnionHopDataFormat::Legacy { .. } => return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]), - msgs::OnionHopDataFormat::NonFinalNode { .. } => return_err!("Got non final data with an HMAC of 0", 0x4000 | 22, &[0;0]), - msgs::OnionHopDataFormat::FinalNode { payment_data, keysend_preimage } => { - if payment_data.is_some() && keysend_preimage.is_some() { - return_err!("We don't support MPP keysend payments", 0x4000|22, &[0;0]); - } else if let Some(data) = payment_data { - PendingHTLCRouting::Receive { - payment_data: data, - incoming_cltv_expiry: msg.cltv_expiry, - } - } else if let Some(payment_preimage) = keysend_preimage { - // We need to check that the sender knows the keysend preimage before processing this - // payment further. Otherwise, an intermediary routing hop forwarding non-keysend-HTLC X - // could discover the final destination of X, by probing the adjacent nodes on the route - // with a keysend payment of identical payment hash to X and observing the processing - // time discrepancies due to a hash collision with X. - let hashed_preimage = PaymentHash(Sha256::hash(&payment_preimage.0).into_inner()); - if hashed_preimage != msg.payment_hash { - return_err!("Payment preimage didn't match payment hash", 0x4000|22, &[0;0]); - } - - PendingHTLCRouting::ReceiveKeysend { - payment_preimage, - incoming_cltv_expiry: msg.cltv_expiry, - } - } else { - return_err!("We require payment_secrets", 0x4000|0x2000|3, &[0;0]); - } + match self.construct_recv_pending_htlc_info(next_hop_data, shared_secret, msg.payment_hash, msg.amount_msat, msg.cltv_expiry) { + Ok(info) => { + // Note that we could obviously respond immediately with an update_fulfill_htlc + // message, however that would leak that we are the recipient of this payment, so + // instead we stay symmetric with the forwarding case, only responding (after a + // delay) once they've send us a commitment_signed! + PendingHTLCStatus::Forward(info) }, - }; - - // Note that we could obviously respond immediately with an update_fulfill_htlc - // message, however that would leak that we are the recipient of this payment, so - // instead we stay symmetric with the forwarding case, only responding (after a - // delay) once they've send us a commitment_signed! - - PendingHTLCStatus::Forward(PendingHTLCInfo { - routing, - payment_hash: msg.payment_hash.clone(), - incoming_shared_secret: shared_secret, - amt_to_forward: next_hop_data.amt_to_forward, - outgoing_cltv_value: next_hop_data.outgoing_cltv_value, - }) + Err(ReceiveError { err_code, err_data, msg }) => return_err!(msg, err_code, &err_data) + } }, onion_utils::Hop::Forward { next_hop_data, next_hop_hmac, new_packet_bytes } => { let mut new_pubkey = msg.onion_routing_packet.public_key.unwrap(); @@ -6593,7 +6625,11 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> pending_events_read.append(&mut channel_closures); } - let our_network_pubkey = PublicKey::from_secret_key(&secp_ctx, &args.keys_manager.get_node_secret()); + let our_network_key = match args.keys_manager.get_node_secret(Recipient::Node) { + Ok(key) => key, + Err(()) => return Err(DecodeError::InvalidValue) + }; + let our_network_pubkey = PublicKey::from_secret_key(&secp_ctx, &our_network_key); if let Some(network_pubkey) = received_network_pubkey { if network_pubkey != our_network_pubkey { log_error!(args.logger, "Key that was generated does not match the existing key."); @@ -6622,7 +6658,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> pending_inbound_payments: Mutex::new(pending_inbound_payments), pending_outbound_payments: Mutex::new(pending_outbound_payments.unwrap()), - our_network_key: args.keys_manager.get_node_secret(), + our_network_key, our_network_pubkey, secp_ctx,