@@ -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,266 @@ 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+ #[ cfg( not( c_bindings) ) ] {
1131+ david. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1132+ Destination :: Node ( alice_id) ;
1133+ }
1134+ #[ cfg( c_bindings) ] {
1135+ david. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . 1 =
1136+ Destination :: Node ( alice_id) ;
1137+ }
1138+
1139+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1140+ alice. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
1141+
1142+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
1143+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1144+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
1145+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1146+
1147+ assert_eq ! ( alice. onion_messenger. next_onion_message_for_peer( charlie_id) , None ) ;
1148+ }
1149+
1150+ /// Check that authentication fails when an invoice is handled using the wrong context (i.e., was
1151+ /// sent over an unexpected blinded path).
1152+ #[ test]
1153+ fn fails_authentication_when_handling_invoice_for_offer ( ) {
1154+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1155+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1156+
1157+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1158+ features. set_onion_messages_optional ( ) ;
1159+ features. set_route_blinding_optional ( ) ;
1160+
1161+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1162+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1163+
1164+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1165+
1166+ let node_chanmgrs = create_node_chanmgrs (
1167+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1168+ ) ;
1169+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1170+
1171+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1172+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1173+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1174+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1175+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1176+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1177+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1178+
1179+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1180+ let alice_id = alice. node . get_our_node_id ( ) ;
1181+ let bob_id = bob. node . get_our_node_id ( ) ;
1182+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1183+ let david_id = david. node . get_our_node_id ( ) ;
1184+
1185+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1186+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1187+
1188+ let offer = alice. node
1189+ . create_offer_builder ( None )
1190+ . unwrap ( )
1191+ . amount_msats ( 10_000_000 )
1192+ . build ( ) . unwrap ( ) ;
1193+ assert_ne ! ( offer. signing_pubkey( ) , Some ( alice_id) ) ;
1194+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
1195+ for path in offer. paths ( ) {
1196+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( bob_id) ) ;
1197+ }
1198+
1199+ // Initiate an invoice request, but abandon tracking it.
1200+ let payment_id_255 = PaymentId ( [ 255 ; 32 ] ) ;
1201+ david. node . pay_for_offer ( & offer, None , None , None , payment_id_255, Retry :: Attempts ( 0 ) , None )
1202+ . unwrap ( ) ;
1203+ david. node . abandon_payment ( payment_id_255) ;
1204+ get_event ! ( david, Event :: InvoiceRequestFailed ) ;
1205+
1206+ // Don't send the invoice request, but grab its reply path to use with a different request.
1207+ let invalid_reply_path = {
1208+ let mut penidng_offers_messages = david. node . pending_offers_messages . lock ( ) . unwrap ( ) ;
1209+ let pending_invoice_request = penidng_offers_messages. pop ( ) . unwrap ( ) ;
1210+ penidng_offers_messages. clear ( ) ;
1211+ #[ cfg( not( c_bindings) ) ] {
1212+ pending_invoice_request. reply_path
1213+ }
1214+ #[ cfg( c_bindings) ] {
1215+ pending_invoice_request. 2
1216+ }
1217+ } ;
1218+
1219+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1220+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
1221+ . unwrap ( ) ;
1222+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1223+
1224+ // Swap out the reply path to force authentication to fail when handling the invoice since it
1225+ // will be sent over the wrong blinded path.
1226+ {
1227+ let mut penidng_offers_messages = david. node . pending_offers_messages . lock ( ) . unwrap ( ) ;
1228+ let mut pending_invoice_request = penidng_offers_messages. first_mut ( ) . unwrap ( ) ;
1229+ #[ cfg( not( c_bindings) ) ] {
1230+ pending_invoice_request. reply_path = invalid_reply_path;
1231+ }
1232+ #[ cfg( c_bindings) ] {
1233+ pending_invoice_request. 2 = invalid_reply_path;
1234+ }
1235+ }
1236+
1237+ connect_peers ( david, bob) ;
1238+
1239+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
1240+ bob. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
1241+
1242+ connect_peers ( alice, charlie) ;
1243+
1244+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1245+ alice. onion_messenger . handle_onion_message ( & bob_id, & onion_message) ;
1246+
1247+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
1248+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1249+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
1250+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1251+
1252+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( charlie_id) . unwrap ( ) ;
1253+ charlie. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
1254+
1255+ let onion_message = charlie. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
1256+ david. onion_messenger . handle_onion_message ( & charlie_id, & onion_message) ;
1257+
1258+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1259+ }
1260+
1261+ /// Check that authentication fails when an invoice is handled using the wrong context (i.e., was
1262+ /// sent directly or over an unexpected blinded path).
1263+ #[ test]
1264+ fn fails_authentication_when_handling_invoice_for_refund ( ) {
1265+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1266+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1267+
1268+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1269+ features. set_onion_messages_optional ( ) ;
1270+ features. set_route_blinding_optional ( ) ;
1271+
1272+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1273+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1274+
1275+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1276+
1277+ let node_chanmgrs = create_node_chanmgrs (
1278+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1279+ ) ;
1280+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1281+
1282+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1283+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1284+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1285+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1286+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1287+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1288+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1289+
1290+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1291+ let alice_id = alice. node . get_our_node_id ( ) ;
1292+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1293+ let david_id = david. node . get_our_node_id ( ) ;
1294+
1295+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1296+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1297+
1298+ let absolute_expiry = Duration :: from_secs ( u64:: MAX ) ;
1299+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1300+ let refund = david. node
1301+ . create_refund_builder ( 10_000_000 , absolute_expiry, payment_id, Retry :: Attempts ( 0 ) , None )
1302+ . unwrap ( )
1303+ . build ( ) . unwrap ( ) ;
1304+ assert_ne ! ( refund. payer_id( ) , david_id) ;
1305+ assert ! ( !refund. paths( ) . is_empty( ) ) ;
1306+ for path in refund. paths ( ) {
1307+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1308+ }
1309+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1310+
1311+ let expected_invoice = alice. node . request_refund_payment ( & refund) . unwrap ( ) ;
1312+
1313+ // Send the invoice directly to David instead of using a blinded path.
1314+ connect_peers ( david, alice) ;
1315+ #[ cfg( not( c_bindings) ) ] {
1316+ alice. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1317+ Destination :: Node ( david_id) ;
1318+ }
1319+ #[ cfg( c_bindings) ] {
1320+ alice. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . 1 =
1321+ Destination :: Node ( david_id) ;
1322+ }
1323+
1324+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
1325+ david. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
1326+
1327+ let invoice = extract_invoice ( david, & onion_message) ;
1328+ assert_eq ! ( invoice, expected_invoice) ;
1329+
1330+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1331+ }
1332+
10731333/// Fails creating or paying an offer when a blinded path cannot be created because no peers are
10741334/// connected.
10751335#[ test]
0 commit comments