@@ -38,21 +38,19 @@ use chain::keysinterface::{ChannelKeys, KeysInterface, InMemoryChannelKeys};
3838use util:: config:: UserConfig ;
3939use util:: { byte_utils, events} ;
4040use util:: ser:: { Readable , ReadableArgs , Writeable , Writer } ;
41- use util:: chacha20:: ChaCha20 ;
41+ use util:: chacha20:: { ChaCha20 , ChaChaReader } ;
4242use util:: logger:: Logger ;
4343use util:: errors:: APIError ;
4444
4545use std:: { cmp, mem} ;
4646use std:: collections:: { HashMap , hash_map, HashSet } ;
47- use std:: io:: Cursor ;
47+ use std:: io:: { Cursor , Read } ;
4848use std:: sync:: { Arc , Mutex , MutexGuard , RwLock } ;
4949use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
5050use std:: time:: Duration ;
5151use std:: marker:: { Sync , Send } ;
5252use std:: ops:: Deref ;
5353
54- const SIXTY_FIVE_ZEROS : [ u8 ; 65 ] = [ 0 ; 65 ] ;
55-
5654// We hold various information about HTLC relay in the HTLC objects in Channel itself:
5755//
5856// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
@@ -906,22 +904,30 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
906904 }
907905
908906 let mut chacha = ChaCha20 :: new ( & rho, & [ 0u8 ; 8 ] ) ;
909- let next_hop_data = {
910- let mut decoded = [ 0 ; 65 ] ;
911- chacha. process ( & msg. onion_routing_packet . hop_data [ 0 ..65 ] , & mut decoded) ;
912- match msgs:: OnionHopData :: read ( & mut Cursor :: new ( & decoded[ ..] ) ) {
907+ let mut chacha_stream = ChaChaReader { chacha : & mut chacha, read : Cursor :: new ( & msg. onion_routing_packet . hop_data [ ..] ) } ;
908+ let ( next_hop_data, next_hop_hmac) = {
909+ match msgs:: OnionHopData :: read ( & mut chacha_stream) {
913910 Err ( err) => {
914911 let error_code = match err {
915912 msgs:: DecodeError :: UnknownVersion => 0x4000 | 1 , // unknown realm byte
913+ msgs:: DecodeError :: UnknownRequiredFeature |
914+ msgs:: DecodeError :: InvalidValue |
915+ msgs:: DecodeError :: ShortRead => 0x4000 | 22 , // invalid_onion_payload
916916 _ => 0x2000 | 2 , // Should never happen
917917 } ;
918918 return_err ! ( "Unable to decode our hop data" , error_code, & [ 0 ; 0 ] ) ;
919919 } ,
920- Ok ( msg) => msg
920+ Ok ( msg) => {
921+ let mut hmac = [ 0 ; 32 ] ;
922+ if let Err ( _) = chacha_stream. read_exact ( & mut hmac[ ..] ) {
923+ return_err ! ( "Unable to decode hop data" , 0x4000 | 22 , & [ 0 ; 0 ] ) ;
924+ }
925+ ( msg, hmac)
926+ } ,
921927 }
922928 } ;
923929
924- let pending_forward_info = if next_hop_data . hmac == [ 0 ; 32 ] {
930+ let pending_forward_info = if next_hop_hmac == [ 0 ; 32 ] {
925931 #[ cfg( test) ]
926932 {
927933 // In tests, make sure that the initial onion pcket data is, at least, non-0.
@@ -931,10 +937,11 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
931937 // as-is (and were originally 0s).
932938 // Of course reverse path calculation is still pretty easy given naive routing
933939 // algorithms, but this fixes the most-obvious case.
934- let mut new_packet_data = [ 0 ; 19 * 65 ] ;
935- chacha. process ( & msg. onion_routing_packet . hop_data [ 65 ..] , & mut new_packet_data[ 0 ..19 * 65 ] ) ;
936- assert_ne ! ( new_packet_data[ 0 ..65 ] , [ 0 ; 65 ] [ ..] ) ;
937- assert_ne ! ( new_packet_data[ ..] , [ 0 ; 19 * 65 ] [ ..] ) ;
940+ let mut next_bytes = [ 0 ; 32 ] ;
941+ chacha_stream. read_exact ( & mut next_bytes) . unwrap ( ) ;
942+ assert_ne ! ( next_bytes[ ..] , [ 0 ; 32 ] [ ..] ) ;
943+ chacha_stream. read_exact ( & mut next_bytes) . unwrap ( ) ;
944+ assert_ne ! ( next_bytes[ ..] , [ 0 ; 32 ] [ ..] ) ;
938945 }
939946
940947 // OUR PAYMENT!
@@ -943,11 +950,11 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
943950 return_err ! ( "The final CLTV expiry is too soon to handle" , 17 , & [ 0 ; 0 ] ) ;
944951 }
945952 // final_incorrect_htlc_amount
946- if next_hop_data. data . amt_to_forward > msg. amount_msat {
953+ if next_hop_data. amt_to_forward > msg. amount_msat {
947954 return_err ! ( "Upstream node sent less than we were supposed to receive in payment" , 19 , & byte_utils:: be64_to_array( msg. amount_msat) ) ;
948955 }
949956 // final_incorrect_cltv_expiry
950- if next_hop_data. data . outgoing_cltv_value != msg. cltv_expiry {
957+ if next_hop_data. outgoing_cltv_value != msg. cltv_expiry {
951958 return_err ! ( "Upstream node set CLTV to the wrong value" , 18 , & byte_utils:: be32_to_array( msg. cltv_expiry) ) ;
952959 }
953960
@@ -961,13 +968,24 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
961968 payment_hash : msg. payment_hash . clone ( ) ,
962969 short_channel_id : 0 ,
963970 incoming_shared_secret : shared_secret,
964- amt_to_forward : next_hop_data. data . amt_to_forward ,
965- outgoing_cltv_value : next_hop_data. data . outgoing_cltv_value ,
971+ amt_to_forward : next_hop_data. amt_to_forward ,
972+ outgoing_cltv_value : next_hop_data. outgoing_cltv_value ,
966973 } )
967974 } else {
968975 let mut new_packet_data = [ 0 ; 20 * 65 ] ;
969- chacha. process ( & msg. onion_routing_packet . hop_data [ 65 ..] , & mut new_packet_data[ 0 ..19 * 65 ] ) ;
970- chacha. process ( & SIXTY_FIVE_ZEROS [ ..] , & mut new_packet_data[ 19 * 65 ..] ) ;
976+ let read_pos = chacha_stream. read ( & mut new_packet_data) . unwrap ( ) ;
977+ #[ cfg( debug_assertions) ]
978+ {
979+ // Check two things:
980+ // a) that the behavior of our stream here will return Ok(0) even if the TLV
981+ // read above emptied out our buffer and the unwrap() wont needlessly panic
982+ // b) that we didn't somehow magically end up with extra data.
983+ let mut t = [ 0 ; 1 ] ;
984+ debug_assert ! ( chacha_stream. read( & mut t) . unwrap( ) == 0 ) ;
985+ }
986+ // Once we've emptied the set of bytes our peer gave us, encrypt 0 bytes until we
987+ // fill the onion hop data we'll forward to our next-hop peer.
988+ chacha_stream. chacha . process_in_place ( & mut new_packet_data[ read_pos..] ) ;
971989
972990 let mut new_pubkey = msg. onion_routing_packet . public_key . unwrap ( ) ;
973991
@@ -986,16 +1004,24 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
9861004 version : 0 ,
9871005 public_key,
9881006 hop_data : new_packet_data,
989- hmac : next_hop_data. hmac . clone ( ) ,
1007+ hmac : next_hop_hmac. clone ( ) ,
1008+ } ;
1009+
1010+ let short_channel_id = match next_hop_data. format {
1011+ msgs:: OnionHopDataFormat :: Legacy { short_channel_id } => short_channel_id,
1012+ msgs:: OnionHopDataFormat :: NonFinalNode { short_channel_id } => short_channel_id,
1013+ msgs:: OnionHopDataFormat :: FinalNode => {
1014+ return_err ! ( "Final Node OnionHopData provided for us as an intermediary node" , 0x4000 | 22 , & [ 0 ; 0 ] ) ;
1015+ } ,
9901016 } ;
9911017
9921018 PendingHTLCStatus :: Forward ( PendingForwardHTLCInfo {
9931019 onion_packet : Some ( outgoing_packet) ,
9941020 payment_hash : msg. payment_hash . clone ( ) ,
995- short_channel_id : next_hop_data . data . short_channel_id ,
1021+ short_channel_id : short_channel_id,
9961022 incoming_shared_secret : shared_secret,
997- amt_to_forward : next_hop_data. data . amt_to_forward ,
998- outgoing_cltv_value : next_hop_data. data . outgoing_cltv_value ,
1023+ amt_to_forward : next_hop_data. amt_to_forward ,
1024+ outgoing_cltv_value : next_hop_data. outgoing_cltv_value ,
9991025 } )
10001026 } ;
10011027
@@ -1137,6 +1163,9 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
11371163 let onion_keys = secp_call ! ( onion_utils:: construct_onion_keys( & self . secp_ctx, & route, & session_priv) ,
11381164 APIError :: RouteError { err: "Pubkey along hop was maliciously selected" } ) ;
11391165 let ( onion_payloads, htlc_msat, htlc_cltv) = onion_utils:: build_onion_payloads ( & route, cur_height) ?;
1166+ if onion_utils:: route_size_insane ( & onion_payloads) {
1167+ return Err ( APIError :: RouteError { err : "Route size too large considering onion data" } ) ;
1168+ }
11401169 let onion_packet = onion_utils:: construct_onion_packet ( onion_payloads, onion_keys, prng_seed, & payment_hash) ;
11411170
11421171 let _ = self . total_consistency_lock . read ( ) . unwrap ( ) ;
0 commit comments