X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fonion_utils.rs;h=605080c7b9298798e45b1a9216f5bad62c810fd3;hb=ae15ba84620f40ed5c80870d254d5eda341f1aba;hp=31f2f7827bcb57c42d7b2a625a842abdaa00ab17;hpb=c2bbfffb1eb249c2c422cf2e9ccac97a34275f7a;p=rust-lightning diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index 31f2f782..605080c7 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -433,11 +433,22 @@ pub(crate) struct DecodedOnionFailure { pub(crate) onion_error_data: Option>, } +/// Note that we always decrypt `packet` in-place here even if the deserialization into +/// [`msgs::DecodedOnionErrorPacket`] ultimately fails. +fn decrypt_onion_error_packet( + packet: &mut Vec, shared_secret: SharedSecret +) -> Result { + let ammag = gen_ammag_from_shared_secret(shared_secret.as_ref()); + let mut chacha = ChaCha20::new(&ammag, &[0u8; 8]); + chacha.process_in_place(packet); + msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(packet)) +} + /// Process failure we got back from upstream on a payment we sent (implying htlc_source is an /// OutboundRoute). #[inline] pub(super) fn process_onion_failure( - secp_ctx: &Secp256k1, logger: &L, htlc_source: &HTLCSource, mut packet_decrypted: Vec + secp_ctx: &Secp256k1, logger: &L, htlc_source: &HTLCSource, mut encrypted_packet: Vec ) -> DecodedOnionFailure where L::Target: Logger { let (path, session_priv, first_hop_htlc_msat) = if let &HTLCSource::OutboundRoute { ref path, ref session_priv, ref first_hop_htlc_msat, .. @@ -491,8 +502,21 @@ pub(super) fn process_onion_failure( Some(hop) => hop, None => { // The failing hop is within a multi-hop blinded path. - error_code_ret = Some(BADONION | PERM | 24); // invalid_onion_blinding - error_packet_ret = Some(vec![0; 32]); + #[cfg(not(test))] { + error_code_ret = Some(BADONION | PERM | 24); // invalid_onion_blinding + error_packet_ret = Some(vec![0; 32]); + } + #[cfg(test)] { + // Actually parse the onion error data in tests so we can check that blinded hops fail + // back correctly. + let err_packet = decrypt_onion_error_packet( + &mut encrypted_packet, shared_secret + ).unwrap(); + error_code_ret = + Some(u16::from_be_bytes(err_packet.failuremsg.get(0..2).unwrap().try_into().unwrap())); + error_packet_ret = Some(err_packet.failuremsg[2..].to_vec()); + } + res = Some(FailureLearnings { network_update: None, short_channel_id: None, payment_failed_permanently: false }); @@ -504,15 +528,7 @@ pub(super) fn process_onion_failure( let amt_to_forward = htlc_msat - route_hop.fee_msat; htlc_msat = amt_to_forward; - let ammag = gen_ammag_from_shared_secret(shared_secret.as_ref()); - - let mut decryption_tmp = Vec::with_capacity(packet_decrypted.len()); - decryption_tmp.resize(packet_decrypted.len(), 0); - let mut chacha = ChaCha20::new(&ammag, &[0u8; 8]); - chacha.process(&packet_decrypted, &mut decryption_tmp[..]); - packet_decrypted = decryption_tmp; - - let err_packet = match msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(&packet_decrypted)) { + let err_packet = match decrypt_onion_error_packet(&mut encrypted_packet, shared_secret) { Ok(p) => p, Err(_) => return };