Skip to content

Commit 8f4e283

Browse files
committed
public static peel_onion method on OnionMessenger
1 parent 989304e commit 8f4e283

File tree

2 files changed

+114
-78
lines changed

2 files changed

+114
-78
lines changed

lightning/src/onion_message/messenger.rs

+113-77
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,16 @@ pub trait CustomOnionMessageHandler {
246246
fn read_custom_message<R: io::Read>(&self, message_type: u64, buffer: &mut R) -> Result<Option<Self::CustomMessage>, msgs::DecodeError>;
247247
}
248248

249+
/// A processed incoming onion message, containing either a Forward (another onion message)
250+
/// or a Receive payload with decrypted contents.
251+
pub enum PeeledOnion<CMH: Deref> where
252+
CMH::Target: CustomOnionMessageHandler,
253+
{
254+
/// Forwarded onion, with the next node id and a new onion
255+
Forward(PublicKey, msgs::OnionMessage),
256+
/// Received onion message, with decrypted contents, path_id, and reply path
257+
Receive(OnionMessageContents<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage>, Option<[u8; 32]>, Option<BlindedPath>)
258+
}
249259

250260
/// Create an onion message with contents `message` to the destination of `path`.
251261
/// Returns (introduction_node_id, onion_msg)
@@ -304,6 +314,101 @@ where
304314
}))
305315
}
306316

317+
/// Decode one layer of an incoming onion message
318+
/// Returns either a Forward (another onion message), or Receive (decrypted content)
319+
pub fn peel_onion<NS: Deref, L: Deref, CMH: Deref, T: CustomOnionMessageContents>(
320+
node_signer: NS, secp_ctx: &Secp256k1<secp256k1::All>, logger: L, custom_handler: CMH,
321+
msg: &msgs::OnionMessage,
322+
) -> Result<PeeledOnion<CMH>, ()>
323+
where
324+
NS::Target: NodeSigner,
325+
L::Target: Logger,
326+
CMH::Target: CustomOnionMessageHandler,
327+
{
328+
let control_tlvs_ss = match node_signer.ecdh(Recipient::Node, &msg.blinding_point, None) {
329+
Ok(ss) => ss,
330+
Err(e) => {
331+
log_error!(logger, "Failed to retrieve node secret: {:?}", e);
332+
return Err(());
333+
}
334+
};
335+
let onion_decode_ss = {
336+
let blinding_factor = {
337+
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
338+
hmac.input(control_tlvs_ss.as_ref());
339+
Hmac::from_engine(hmac).into_inner()
340+
};
341+
match node_signer.ecdh(Recipient::Node, &msg.onion_routing_packet.public_key,
342+
Some(&Scalar::from_be_bytes(blinding_factor).unwrap()))
343+
{
344+
Ok(ss) => ss.secret_bytes(),
345+
Err(()) => {
346+
log_trace!(logger, "Failed to compute onion packet shared secret");
347+
return Err(());
348+
}
349+
}
350+
};
351+
match onion_utils::decode_next_untagged_hop(
352+
onion_decode_ss, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
353+
(control_tlvs_ss, custom_handler.deref(), logger.deref())
354+
) {
355+
Ok((Payload::Receive::<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage> {
356+
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
357+
}, None)) => {
358+
Ok(PeeledOnion::Receive(message, path_id, reply_path))
359+
},
360+
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
361+
next_node_id, next_blinding_override
362+
})), Some((next_hop_hmac, new_packet_bytes)))) => {
363+
// TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
364+
// blinded hop and this onion message is destined for us. In this situation, we should keep
365+
// unwrapping the onion layers to get to the final payload. Since we don't have the option
366+
// of creating blinded paths with dummy hops currently, we should be ok to not handle this
367+
// for now.
368+
let new_pubkey = match onion_utils::next_hop_pubkey(&secp_ctx, msg.onion_routing_packet.public_key, &onion_decode_ss) {
369+
Ok(pk) => pk,
370+
Err(e) => {
371+
log_trace!(logger, "Failed to compute next hop packet pubkey: {}", e);
372+
return Err(())
373+
}
374+
};
375+
let outgoing_packet = Packet {
376+
version: 0,
377+
public_key: new_pubkey,
378+
hop_data: new_packet_bytes,
379+
hmac: next_hop_hmac,
380+
};
381+
let onion_message = msgs::OnionMessage {
382+
blinding_point: match next_blinding_override {
383+
Some(blinding_point) => blinding_point,
384+
None => {
385+
match onion_utils::next_hop_pubkey(
386+
&secp_ctx, msg.blinding_point, control_tlvs_ss.as_ref()
387+
) {
388+
Ok(bp) => bp,
389+
Err(e) => {
390+
log_trace!(logger, "Failed to compute next blinding point: {}", e);
391+
return Err(())
392+
}
393+
}
394+
}
395+
},
396+
onion_routing_packet: outgoing_packet,
397+
};
398+
399+
Ok(PeeledOnion::Forward(next_node_id, onion_message))
400+
},
401+
Err(e) => {
402+
log_trace!(logger, "Errored decoding onion message packet: {:?}", e);
403+
Err(())
404+
},
405+
_ => {
406+
log_trace!(logger, "Received bogus onion message packet, either the sender encoded a final hop as a forwarding hop or vice versa");
407+
Err(())
408+
},
409+
}
410+
}
411+
307412
impl<ES: Deref, NS: Deref, L: Deref, MR: Deref, OMH: Deref, CMH: Deref>
308413
OnionMessenger<ES, NS, L, MR, OMH, CMH>
309414
where
@@ -457,40 +562,13 @@ where
457562
/// soon we'll delegate the onion message to a handler that can generate invoices or send
458563
/// payments.
459564
fn handle_onion_message(&self, _peer_node_id: &PublicKey, msg: &msgs::OnionMessage) {
460-
let control_tlvs_ss = match self.node_signer.ecdh(Recipient::Node, &msg.blinding_point, None) {
461-
Ok(ss) => ss,
462-
Err(e) => {
463-
log_error!(self.logger, "Failed to retrieve node secret: {:?}", e);
464-
return
465-
}
466-
};
467-
let onion_decode_ss = {
468-
let blinding_factor = {
469-
let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
470-
hmac.input(control_tlvs_ss.as_ref());
471-
Hmac::from_engine(hmac).into_inner()
472-
};
473-
match self.node_signer.ecdh(Recipient::Node, &msg.onion_routing_packet.public_key,
474-
Some(&Scalar::from_be_bytes(blinding_factor).unwrap()))
475-
{
476-
Ok(ss) => ss.secret_bytes(),
477-
Err(()) => {
478-
log_trace!(self.logger, "Failed to compute onion packet shared secret");
479-
return
480-
}
481-
}
482-
};
483-
match onion_utils::decode_next_untagged_hop(
484-
onion_decode_ss, &msg.onion_routing_packet.hop_data[..], msg.onion_routing_packet.hmac,
485-
(control_tlvs_ss, &*self.custom_handler, &*self.logger)
565+
match peel_onion::<NS, L, CMH, <<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage>(
566+
&self.node_signer, &self.secp_ctx, &self.logger, &self.custom_handler, msg
486567
) {
487-
Ok((Payload::Receive::<<<CMH as Deref>::Target as CustomOnionMessageHandler>::CustomMessage> {
488-
message, control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id }), reply_path,
489-
}, None)) => {
568+
Ok(PeeledOnion::Receive(message, path_id, reply_path)) => {
490569
log_trace!(self.logger,
491570
"Received an onion message with path_id {:02x?} and {} reply_path",
492571
path_id, if reply_path.is_some() { "a" } else { "no" });
493-
494572
let response = match message {
495573
OnionMessageContents::Offers(msg) => {
496574
self.offers_handler.handle_message(msg)
@@ -501,50 +579,11 @@ where
501579
.map(|msg| OnionMessageContents::Custom(msg))
502580
},
503581
};
504-
505582
if let Some(response) = response {
506583
self.respond_with_onion_message(response, path_id, reply_path);
507584
}
508585
},
509-
Ok((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
510-
next_node_id, next_blinding_override
511-
})), Some((next_hop_hmac, new_packet_bytes)))) => {
512-
// TODO: we need to check whether `next_node_id` is our node, in which case this is a dummy
513-
// blinded hop and this onion message is destined for us. In this situation, we should keep
514-
// unwrapping the onion layers to get to the final payload. Since we don't have the option
515-
// of creating blinded paths with dummy hops currently, we should be ok to not handle this
516-
// for now.
517-
let new_pubkey = match onion_utils::next_hop_pubkey(&self.secp_ctx, msg.onion_routing_packet.public_key, &onion_decode_ss) {
518-
Ok(pk) => pk,
519-
Err(e) => {
520-
log_trace!(self.logger, "Failed to compute next hop packet pubkey: {}", e);
521-
return
522-
}
523-
};
524-
let outgoing_packet = Packet {
525-
version: 0,
526-
public_key: new_pubkey,
527-
hop_data: new_packet_bytes,
528-
hmac: next_hop_hmac,
529-
};
530-
let onion_message = msgs::OnionMessage {
531-
blinding_point: match next_blinding_override {
532-
Some(blinding_point) => blinding_point,
533-
None => {
534-
match onion_utils::next_hop_pubkey(
535-
&self.secp_ctx, msg.blinding_point, control_tlvs_ss.as_ref()
536-
) {
537-
Ok(bp) => bp,
538-
Err(e) => {
539-
log_trace!(self.logger, "Failed to compute next blinding point: {}", e);
540-
return
541-
}
542-
}
543-
}
544-
},
545-
onion_routing_packet: outgoing_packet,
546-
};
547-
586+
Ok(PeeledOnion::Forward(next_node_id, onion_message)) => {
548587
let mut pending_per_peer_msgs = self.pending_messages.lock().unwrap();
549588
if outbound_buffer_full(&next_node_id, &pending_per_peer_msgs) {
550589
log_trace!(self.logger, "Dropping forwarded onion message to peer {:?}: outbound buffer full", next_node_id);
@@ -563,15 +602,12 @@ where
563602
e.get_mut().push_back(onion_message);
564603
log_trace!(self.logger, "Forwarding an onion message to peer {}", next_node_id);
565604
}
566-
};
605+
}
567606
},
568607
Err(e) => {
569-
log_trace!(self.logger, "Errored decoding onion message packet: {:?}", e);
570-
},
571-
_ => {
572-
log_trace!(self.logger, "Received bogus onion message packet, either the sender encoded a final hop as a forwarding hop or vice versa");
573-
},
574-
};
608+
log_error!(self.logger, "Failed to process onion message {:?}", e);
609+
}
610+
}
575611
}
576612

577613
fn peer_connected(&self, their_node_id: &PublicKey, init: &msgs::Init, _inbound: bool) -> Result<(), ()> {

lightning/src/onion_message/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ mod packet;
2727
mod functional_tests;
2828

2929
// Re-export structs so they can be imported with just the `onion_message::` module prefix.
30-
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
30+
pub use self::messenger::{CustomOnionMessageContents, CustomOnionMessageHandler, DefaultMessageRouter, Destination, MessageRouter, OnionMessageContents, OnionMessagePath, OnionMessenger, PeeledOnion, SendError, SimpleArcOnionMessenger, SimpleRefOnionMessenger};
3131
pub use self::offers::{OffersMessage, OffersMessageHandler};
3232
pub use self::packet::Packet;
3333
pub(crate) use self::packet::ControlTlvs;

0 commit comments

Comments
 (0)