@@ -54,7 +54,7 @@ use crate::offers::invoice::Bolt12Invoice;
5454use crate :: offers:: invoice_error:: InvoiceError ;
5555use crate :: offers:: invoice_request:: { InvoiceRequest , InvoiceRequestFields } ;
5656use crate :: offers:: parse:: Bolt12SemanticError ;
57- use crate :: onion_message:: messenger:: PeeledOnion ;
57+ use crate :: onion_message:: messenger:: { Destination , PeeledOnion } ;
5858use crate :: onion_message:: offers:: OffersMessage ;
5959use crate :: onion_message:: packet:: ParsedOnionMessageContents ;
6060use crate :: routing:: gossip:: { NodeAlias , NodeId } ;
@@ -1070,6 +1070,244 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
10701070 }
10711071}
10721072
1073+ /// Check that authentication fails when an invoice request is handled using the wrong context
1074+ /// (i.e., was sent directly or over an unexpected blinded path).
1075+ #[ test]
1076+ fn fails_authentication_when_handling_invoice_request ( ) {
1077+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1078+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1079+
1080+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1081+ features. set_onion_messages_optional ( ) ;
1082+ features. set_route_blinding_optional ( ) ;
1083+
1084+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1085+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1086+
1087+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1088+
1089+ let node_chanmgrs = create_node_chanmgrs (
1090+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1091+ ) ;
1092+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1093+
1094+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1095+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1096+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1097+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1098+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1099+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1100+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1101+
1102+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1103+ let alice_id = alice. node . get_our_node_id ( ) ;
1104+ let bob_id = bob. node . get_our_node_id ( ) ;
1105+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1106+ let david_id = david. node . get_our_node_id ( ) ;
1107+
1108+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1109+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1110+
1111+ let offer = alice. node
1112+ . create_offer_builder ( None )
1113+ . unwrap ( )
1114+ . amount_msats ( 10_000_000 )
1115+ . build ( ) . unwrap ( ) ;
1116+ assert_eq ! ( offer. metadata( ) , None ) ;
1117+ assert_ne ! ( offer. signing_pubkey( ) , Some ( alice_id) ) ;
1118+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
1119+ for path in offer. paths ( ) {
1120+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( bob_id) ) ;
1121+ }
1122+
1123+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1124+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
1125+ . unwrap ( ) ;
1126+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1127+
1128+ // Send the invoice request directly to Alice instead of using a blinded path.
1129+ connect_peers ( david, alice) ;
1130+ david. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1131+ Destination :: Node ( alice_id) ;
1132+
1133+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1134+ alice. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
1135+
1136+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
1137+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1138+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
1139+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1140+
1141+ assert_eq ! ( alice. onion_messenger. next_onion_message_for_peer( charlie_id) , None ) ;
1142+ }
1143+
1144+ /// Check that authentication fails when an invoice is handled using the wrong context (i.e., was
1145+ /// sent over an unexpected blinded path).
1146+ #[ test]
1147+ fn fails_authentication_when_handling_invoice_for_offer ( ) {
1148+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1149+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1150+
1151+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1152+ features. set_onion_messages_optional ( ) ;
1153+ features. set_route_blinding_optional ( ) ;
1154+
1155+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1156+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1157+
1158+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1159+
1160+ let node_chanmgrs = create_node_chanmgrs (
1161+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1162+ ) ;
1163+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1164+
1165+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1166+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1167+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1168+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1169+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1170+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1171+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1172+
1173+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1174+ let alice_id = alice. node . get_our_node_id ( ) ;
1175+ let bob_id = bob. node . get_our_node_id ( ) ;
1176+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1177+ let david_id = david. node . get_our_node_id ( ) ;
1178+
1179+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1180+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1181+
1182+ let offer = alice. node
1183+ . create_offer_builder ( None )
1184+ . unwrap ( )
1185+ . amount_msats ( 10_000_000 )
1186+ . build ( ) . unwrap ( ) ;
1187+ assert_ne ! ( offer. signing_pubkey( ) , Some ( alice_id) ) ;
1188+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
1189+ for path in offer. paths ( ) {
1190+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( bob_id) ) ;
1191+ }
1192+
1193+ // Initiate an invoice request, but abandon tracking it.
1194+ let payment_id_255 = PaymentId ( [ 255 ; 32 ] ) ;
1195+ david. node . pay_for_offer ( & offer, None , None , None , payment_id_255, Retry :: Attempts ( 0 ) , None )
1196+ . unwrap ( ) ;
1197+ david. node . abandon_payment ( payment_id_255) ;
1198+ get_event ! ( david, Event :: InvoiceRequestFailed ) ;
1199+
1200+ // Don't send the invoice request, but grab its reply path to use with a different request.
1201+ let invalid_reply_path = {
1202+ let mut penidng_offers_messages = david. node . pending_offers_messages . lock ( ) . unwrap ( ) ;
1203+ let pending_invoice_request = penidng_offers_messages. pop ( ) . unwrap ( ) ;
1204+ penidng_offers_messages. clear ( ) ;
1205+ pending_invoice_request. reply_path
1206+ } ;
1207+
1208+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1209+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
1210+ . unwrap ( ) ;
1211+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1212+
1213+ // Swap out the reply path to force authentication to fail when handling the invoice since it
1214+ // will be sent over the wrong blinded path.
1215+ {
1216+ let mut penidng_offers_messages = david. node . pending_offers_messages . lock ( ) . unwrap ( ) ;
1217+ let mut pending_invoice_request = penidng_offers_messages. first_mut ( ) . unwrap ( ) ;
1218+ pending_invoice_request. reply_path = invalid_reply_path;
1219+ }
1220+
1221+ connect_peers ( david, bob) ;
1222+
1223+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
1224+ bob. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
1225+
1226+ connect_peers ( alice, charlie) ;
1227+
1228+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1229+ alice. onion_messenger . handle_onion_message ( & bob_id, & onion_message) ;
1230+
1231+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
1232+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1233+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
1234+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1235+
1236+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( charlie_id) . unwrap ( ) ;
1237+ charlie. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
1238+
1239+ let onion_message = charlie. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
1240+ david. onion_messenger . handle_onion_message ( & charlie_id, & onion_message) ;
1241+
1242+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1243+ }
1244+
1245+ /// Check that authentication fails when an invoice is handled using the wrong context (i.e., was
1246+ /// sent directly or over an unexpected blinded path).
1247+ #[ test]
1248+ fn fails_authentication_when_handling_invoice_for_refund ( ) {
1249+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1250+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1251+
1252+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1253+ features. set_onion_messages_optional ( ) ;
1254+ features. set_route_blinding_optional ( ) ;
1255+
1256+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1257+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1258+
1259+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1260+
1261+ let node_chanmgrs = create_node_chanmgrs (
1262+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1263+ ) ;
1264+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1265+
1266+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1267+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1268+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1269+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1270+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1271+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1272+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1273+
1274+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1275+ let alice_id = alice. node . get_our_node_id ( ) ;
1276+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1277+ let david_id = david. node . get_our_node_id ( ) ;
1278+
1279+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1280+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1281+
1282+ let absolute_expiry = Duration :: from_secs ( u64:: MAX ) ;
1283+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1284+ let refund = david. node
1285+ . create_refund_builder ( 10_000_000 , absolute_expiry, payment_id, Retry :: Attempts ( 0 ) , None )
1286+ . unwrap ( )
1287+ . build ( ) . unwrap ( ) ;
1288+ assert_ne ! ( refund. payer_id( ) , david_id) ;
1289+ assert ! ( !refund. paths( ) . is_empty( ) ) ;
1290+ for path in refund. paths ( ) {
1291+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1292+ }
1293+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1294+
1295+ let expected_invoice = alice. node . request_refund_payment ( & refund) . unwrap ( ) ;
1296+
1297+ // Send the invoice directly to David instead of using a blinded path.
1298+ connect_peers ( david, alice) ;
1299+ alice. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1300+ Destination :: Node ( david_id) ;
1301+
1302+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
1303+ david. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
1304+
1305+ let invoice = extract_invoice ( david, & onion_message) ;
1306+ assert_eq ! ( invoice, expected_invoice) ;
1307+
1308+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1309+ }
1310+
10731311/// Fails creating or paying an offer when a blinded path cannot be created because no peers are
10741312/// connected.
10751313#[ test]
0 commit comments