@@ -14,13 +14,13 @@ use bitcoin::hashes::sha256::Hash as Sha256;
14
14
use bitcoin:: secp256k1:: { self , PublicKey , Secp256k1 , SecretKey } ;
15
15
use bitcoin:: secp256k1:: ecdh:: SharedSecret ;
16
16
17
- use chain:: keysinterface:: { InMemorySigner , KeysInterface , KeysManager , Sign } ;
17
+ use chain:: keysinterface:: { InMemorySigner , KeysInterface , KeysManager , Recipient , Sign } ;
18
18
use ln:: msgs:: { self , DecodeError , OnionMessageHandler } ;
19
19
use ln:: onion_utils;
20
- use util:: chacha20poly1305rfc:: ChaChaPolyWriteAdapter ;
20
+ use util:: chacha20poly1305rfc:: { ChaChaPolyReadAdapter , ChaChaPolyWriteAdapter } ;
21
21
use util:: events:: { MessageSendEvent , MessageSendEventsProvider } ;
22
22
use util:: logger:: Logger ;
23
- use util:: ser:: { Readable , ReadableArgs , VecWriter , Writeable , Writer } ;
23
+ use util:: ser:: { FixedLengthReader , LengthReadableArgs , Readable , ReadableArgs , VecWriter , Writeable , Writer } ;
24
24
25
25
use core:: mem;
26
26
use core:: ops:: Deref ;
@@ -130,6 +130,41 @@ impl Writeable for (Payload, SharedSecret) {
130
130
}
131
131
}
132
132
133
+ /// Reads of `Payload`s are parameterized by the `rho` of a `SharedSecret`, which is used to decrypt
134
+ /// the onion message payload's `encrypted_data` field.
135
+ impl ReadableArgs < SharedSecret > for Payload {
136
+ fn read < R : Read > ( mut r : & mut R , encrypted_tlvs_ss : SharedSecret ) -> Result < Self , DecodeError > {
137
+ use bitcoin:: consensus:: encode:: { Decodable , Error , VarInt } ;
138
+ let v: VarInt = Decodable :: consensus_decode ( & mut r)
139
+ . map_err ( |e| match e {
140
+ Error :: Io ( ioe) => DecodeError :: from ( ioe) ,
141
+ _ => DecodeError :: InvalidValue
142
+ } ) ?;
143
+ if v. 0 == 0 { // 0-length payload
144
+ return Err ( DecodeError :: InvalidValue )
145
+ }
146
+
147
+ let mut rd = FixedLengthReader :: new ( r, v. 0 ) ;
148
+ // TODO: support reply paths
149
+ let mut _reply_path_bytes: Option < Vec < u8 > > = Some ( Vec :: new ( ) ) ;
150
+ let mut read_adapter: Option < ChaChaPolyReadAdapter < ControlTlvs > > = None ;
151
+ let ( rho, _) = onion_utils:: gen_rho_mu_from_shared_secret ( & encrypted_tlvs_ss. secret_bytes ( ) ) ;
152
+ decode_tlv_stream ! ( & mut rd, {
153
+ ( 2 , _reply_path_bytes, vec_type) ,
154
+ ( 4 , read_adapter, ( option: LengthReadableArgs , rho) )
155
+ } ) ;
156
+ rd. eat_remaining ( ) . map_err ( |_| DecodeError :: ShortRead ) ?;
157
+
158
+ if read_adapter. is_none ( ) {
159
+ return Err ( DecodeError :: InvalidValue )
160
+ }
161
+
162
+ Ok ( Payload {
163
+ encrypted_tlvs : EncryptedTlvs :: Unblinded ( read_adapter. unwrap ( ) . readable ) ,
164
+ } )
165
+ }
166
+ }
167
+
133
168
/// Onion messages contain an encrypted TLV stream. This can be supplied by someone else, in the
134
169
/// case that we're sending to a blinded route, or created by us if we're constructing payloads for
135
170
/// unblinded hops in the onion message's path.
@@ -388,7 +423,93 @@ impl<Signer: Sign, K: Deref, L: Deref> OnionMessageHandler for OnionMessenger<Si
388
423
where K :: Target : KeysInterface < Signer = Signer > ,
389
424
L :: Target : Logger ,
390
425
{
391
- fn handle_onion_message ( & self , _peer_node_id : & PublicKey , msg : & msgs:: OnionMessage ) { }
426
+ fn handle_onion_message ( & self , _peer_node_id : & PublicKey , msg : & msgs:: OnionMessage ) {
427
+ let node_secret = match self . keys_manager . get_node_secret ( Recipient :: Node ) {
428
+ Ok ( secret) => secret,
429
+ Err ( e) => {
430
+ log_trace ! ( self . logger, "Failed to retrieve node secret: {:?}" , e) ;
431
+ return
432
+ }
433
+ } ;
434
+ let encrypted_data_ss = SharedSecret :: new ( & msg. blinding_point , & node_secret) ;
435
+ let onion_decode_shared_secret = {
436
+ let blinding_factor = {
437
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( b"blinded_node_id" ) ;
438
+ hmac. input ( encrypted_data_ss. as_ref ( ) ) ;
439
+ Hmac :: from_engine ( hmac) . into_inner ( )
440
+ } ;
441
+ let mut blinded_priv = node_secret. clone ( ) ;
442
+ if let Err ( e) = blinded_priv. mul_assign ( & blinding_factor) {
443
+ log_trace ! ( self . logger, "Failed to compute blinded public key: {}" , e) ;
444
+ return
445
+ }
446
+ if let Err ( _) = msg. onion_routing_packet . public_key {
447
+ log_trace ! ( self . logger, "Failed to accept/forward incoming onion message: invalid ephemeral pubkey" ) ;
448
+ return
449
+ }
450
+ SharedSecret :: new ( & msg. onion_routing_packet . public_key . unwrap ( ) , & blinded_priv) . secret_bytes ( )
451
+ } ;
452
+ match onion_utils:: decode_next_message_hop ( onion_decode_shared_secret, & msg. onion_routing_packet . hop_data [ ..] , msg. onion_routing_packet . hmac , encrypted_data_ss) {
453
+ Ok ( onion_utils:: MessageHop :: Receive ( Payload {
454
+ encrypted_tlvs : EncryptedTlvs :: Unblinded ( ControlTlvs :: Receive { path_id } )
455
+ } ) ) => {
456
+ log_info ! ( self . logger, "Received an onion message with path_id: {:02x?}" , path_id) ;
457
+ } ,
458
+ Ok ( onion_utils:: MessageHop :: Forward {
459
+ next_hop_data : Payload {
460
+ encrypted_tlvs : EncryptedTlvs :: Unblinded ( ControlTlvs :: Receive { path_id } ) ,
461
+ } , .. } ) => {
462
+ // We received an onion message that had fake extra hops at the end of its blinded route.
463
+ // TODO support adding extra hops to blinded routes and test this case
464
+ log_info ! ( self . logger, "Received an onion message with path_id: {:02x?}" , path_id) ;
465
+ } ,
466
+ Ok ( onion_utils:: MessageHop :: Forward {
467
+ next_hop_data : Payload {
468
+ encrypted_tlvs : EncryptedTlvs :: Unblinded ( ControlTlvs :: Forward { next_node_id, next_blinding_override } ) ,
469
+ } ,
470
+ next_hop_hmac, new_packet_bytes
471
+ } ) => {
472
+ let new_pubkey = msg. onion_routing_packet . public_key . unwrap ( ) ;
473
+ let outgoing_packet = Packet {
474
+ version : 0 ,
475
+ public_key : onion_utils:: next_hop_packet_pubkey ( & self . secp_ctx , new_pubkey, & onion_decode_shared_secret) ,
476
+ hop_data : new_packet_bytes. to_vec ( ) ,
477
+ hmac : next_hop_hmac. clone ( ) ,
478
+ } ;
479
+
480
+ let mut pending_msg_events = self . pending_msg_events . lock ( ) . unwrap ( ) ;
481
+ pending_msg_events. push ( MessageSendEvent :: SendOnionMessage {
482
+ node_id : next_node_id,
483
+ msg : msgs:: OnionMessage {
484
+ blinding_point : match next_blinding_override {
485
+ Some ( blinding_point) => blinding_point,
486
+ None => {
487
+ let blinding_factor = {
488
+ let mut sha = Sha256 :: engine ( ) ;
489
+ sha. input ( & msg. blinding_point . serialize ( ) [ ..] ) ;
490
+ sha. input ( encrypted_data_ss. as_ref ( ) ) ;
491
+ Sha256 :: from_engine ( sha) . into_inner ( )
492
+ } ;
493
+ let mut next_blinding_point = msg. blinding_point . clone ( ) ;
494
+ if let Err ( e) = next_blinding_point. mul_assign ( & self . secp_ctx , & blinding_factor[ ..] ) {
495
+ log_trace ! ( self . logger, "Failed to compute next blinding point: {}" , e) ;
496
+ return
497
+ }
498
+ next_blinding_point
499
+ } ,
500
+ } ,
501
+ len : outgoing_packet. len ( ) ,
502
+ onion_routing_packet : outgoing_packet,
503
+ } ,
504
+ } ) ;
505
+ } ,
506
+ Err ( e) => {
507
+ log_trace ! ( self . logger, "Errored decoding onion message packet: {:?}" , e) ;
508
+ } ,
509
+ _ => { } // Unreachable unless someone encodes a `Forward` payload as the final payload, which
510
+ // is bogus and should be fine to drop
511
+ } ;
512
+ }
392
513
}
393
514
394
515
impl < Signer : Sign , K : Deref , L : Deref > MessageSendEventsProvider for OnionMessenger < Signer , K , L >
0 commit comments