@@ -38,21 +38,19 @@ use chain::keysinterface::{ChannelKeys, KeysInterface, InMemoryChannelKeys};
38
38
use util:: config:: UserConfig ;
39
39
use util:: { byte_utils, events} ;
40
40
use util:: ser:: { Readable , ReadableArgs , Writeable , Writer } ;
41
- use util:: chacha20:: ChaCha20 ;
41
+ use util:: chacha20:: { ChaCha20 , ChaChaReader } ;
42
42
use util:: logger:: Logger ;
43
43
use util:: errors:: APIError ;
44
44
45
45
use std:: { cmp, mem} ;
46
46
use std:: collections:: { HashMap , hash_map, HashSet } ;
47
- use std:: io:: Cursor ;
47
+ use std:: io:: { Cursor , Read } ;
48
48
use std:: sync:: { Arc , Mutex , MutexGuard , RwLock } ;
49
49
use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
50
50
use std:: time:: Duration ;
51
51
use std:: marker:: { Sync , Send } ;
52
52
use std:: ops:: Deref ;
53
53
54
- const SIXTY_FIVE_ZEROS : [ u8 ; 65 ] = [ 0 ; 65 ] ;
55
-
56
54
// We hold various information about HTLC relay in the HTLC objects in Channel itself:
57
55
//
58
56
// 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
906
904
}
907
905
908
906
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) {
913
910
Err ( err) => {
914
911
let error_code = match err {
915
912
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
916
916
_ => 0x2000 | 2 , // Should never happen
917
917
} ;
918
918
return_err ! ( "Unable to decode our hop data" , error_code, & [ 0 ; 0 ] ) ;
919
919
} ,
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
+ } ,
921
927
}
922
928
} ;
923
929
924
- let pending_forward_info = if next_hop_data . hmac == [ 0 ; 32 ] {
930
+ let pending_forward_info = if next_hop_hmac == [ 0 ; 32 ] {
925
931
#[ cfg( test) ]
926
932
{
927
933
// 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
931
937
// as-is (and were originally 0s).
932
938
// Of course reverse path calculation is still pretty easy given naive routing
933
939
// 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 ] [ ..] ) ;
938
945
}
939
946
940
947
// OUR PAYMENT!
@@ -943,11 +950,11 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
943
950
return_err ! ( "The final CLTV expiry is too soon to handle" , 17 , & [ 0 ; 0 ] ) ;
944
951
}
945
952
// 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 {
947
954
return_err ! ( "Upstream node sent less than we were supposed to receive in payment" , 19 , & byte_utils:: be64_to_array( msg. amount_msat) ) ;
948
955
}
949
956
// 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 {
951
958
return_err ! ( "Upstream node set CLTV to the wrong value" , 18 , & byte_utils:: be32_to_array( msg. cltv_expiry) ) ;
952
959
}
953
960
@@ -961,13 +968,24 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
961
968
payment_hash : msg. payment_hash . clone ( ) ,
962
969
short_channel_id : 0 ,
963
970
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 ,
966
973
} )
967
974
} else {
968
975
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..] ) ;
971
989
972
990
let mut new_pubkey = msg. onion_routing_packet . public_key . unwrap ( ) ;
973
991
@@ -986,16 +1004,24 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
986
1004
version : 0 ,
987
1005
public_key,
988
1006
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
+ } ,
990
1016
} ;
991
1017
992
1018
PendingHTLCStatus :: Forward ( PendingForwardHTLCInfo {
993
1019
onion_packet : Some ( outgoing_packet) ,
994
1020
payment_hash : msg. payment_hash . clone ( ) ,
995
- short_channel_id : next_hop_data . data . short_channel_id ,
1021
+ short_channel_id : short_channel_id,
996
1022
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 ,
999
1025
} )
1000
1026
} ;
1001
1027
@@ -1137,6 +1163,9 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
1137
1163
let onion_keys = secp_call ! ( onion_utils:: construct_onion_keys( & self . secp_ctx, & route, & session_priv) ,
1138
1164
APIError :: RouteError { err: "Pubkey along hop was maliciously selected" } ) ;
1139
1165
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
+ }
1140
1169
let onion_packet = onion_utils:: construct_onion_packet ( onion_payloads, onion_keys, prng_seed, & payment_hash) ;
1141
1170
1142
1171
let _ = self . total_consistency_lock . read ( ) . unwrap ( ) ;
0 commit comments