@@ -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 } ;
@@ -1234,6 +1234,346 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
12341234 }
12351235}
12361236
1237+ /// Check that authentication fails when an invoice request is handled using the wrong context
1238+ /// (i.e., was sent directly or over an unexpected blinded path).
1239+ #[ test]
1240+ fn fails_authentication_when_handling_invoice_request ( ) {
1241+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1242+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1243+
1244+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1245+ features. set_onion_messages_optional ( ) ;
1246+ features. set_route_blinding_optional ( ) ;
1247+
1248+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1249+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1250+
1251+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1252+
1253+ let node_chanmgrs = create_node_chanmgrs (
1254+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1255+ ) ;
1256+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1257+
1258+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1259+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1260+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1261+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1262+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1263+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1264+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1265+
1266+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1267+ let alice_id = alice. node . get_our_node_id ( ) ;
1268+ let bob_id = bob. node . get_our_node_id ( ) ;
1269+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1270+ let david_id = david. node . get_our_node_id ( ) ;
1271+
1272+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1273+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1274+
1275+ let offer = alice. node
1276+ . create_offer_builder ( None )
1277+ . unwrap ( )
1278+ . amount_msats ( 10_000_000 )
1279+ . build ( ) . unwrap ( ) ;
1280+ assert_eq ! ( offer. metadata( ) , None ) ;
1281+ assert_ne ! ( offer. signing_pubkey( ) , Some ( alice_id) ) ;
1282+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
1283+ for path in offer. paths ( ) {
1284+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( bob_id) ) ;
1285+ }
1286+
1287+ let invalid_path = alice. node
1288+ . create_offer_builder ( None )
1289+ . unwrap ( )
1290+ . build ( ) . unwrap ( )
1291+ . paths ( ) . first ( ) . unwrap ( )
1292+ . clone ( ) ;
1293+ assert_eq ! ( invalid_path. introduction_node, IntroductionNode :: NodeId ( bob_id) ) ;
1294+
1295+ // Send the invoice request directly to Alice instead of using a blinded path.
1296+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1297+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
1298+ . unwrap ( ) ;
1299+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1300+
1301+ connect_peers ( david, alice) ;
1302+ #[ cfg( not( c_bindings) ) ] {
1303+ david. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1304+ Destination :: Node ( alice_id) ;
1305+ }
1306+ #[ cfg( c_bindings) ] {
1307+ david. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . 1 =
1308+ Destination :: Node ( alice_id) ;
1309+ }
1310+
1311+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1312+ alice. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
1313+
1314+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
1315+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1316+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
1317+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1318+
1319+ assert_eq ! ( alice. onion_messenger. next_onion_message_for_peer( charlie_id) , None ) ;
1320+
1321+ david. node . abandon_payment ( payment_id) ;
1322+ get_event ! ( david, Event :: InvoiceRequestFailed ) ;
1323+
1324+ // Send the invoice request to Alice using an invalid blinded path.
1325+ let payment_id = PaymentId ( [ 2 ; 32 ] ) ;
1326+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
1327+ . unwrap ( ) ;
1328+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1329+
1330+ #[ cfg( not( c_bindings) ) ] {
1331+ david. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1332+ Destination :: BlindedPath ( invalid_path) ;
1333+ }
1334+ #[ cfg( c_bindings) ] {
1335+ david. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . 1 =
1336+ Destination :: BlindedPath ( invalid_path) ;
1337+ }
1338+
1339+ connect_peers ( david, bob) ;
1340+
1341+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
1342+ bob. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
1343+
1344+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1345+ alice. onion_messenger . handle_onion_message ( & bob_id, & onion_message) ;
1346+
1347+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
1348+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1349+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
1350+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1351+
1352+ assert_eq ! ( alice. onion_messenger. next_onion_message_for_peer( charlie_id) , None ) ;
1353+ }
1354+
1355+ /// Check that authentication fails when an invoice is handled using the wrong context (i.e., was
1356+ /// sent over an unexpected blinded path).
1357+ #[ test]
1358+ fn fails_authentication_when_handling_invoice_for_offer ( ) {
1359+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1360+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1361+
1362+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1363+ features. set_onion_messages_optional ( ) ;
1364+ features. set_route_blinding_optional ( ) ;
1365+
1366+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1367+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1368+
1369+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1370+
1371+ let node_chanmgrs = create_node_chanmgrs (
1372+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1373+ ) ;
1374+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1375+
1376+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1377+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1378+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1379+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1380+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1381+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1382+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1383+
1384+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1385+ let alice_id = alice. node . get_our_node_id ( ) ;
1386+ let bob_id = bob. node . get_our_node_id ( ) ;
1387+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1388+ let david_id = david. node . get_our_node_id ( ) ;
1389+
1390+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1391+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1392+
1393+ let offer = alice. node
1394+ . create_offer_builder ( None )
1395+ . unwrap ( )
1396+ . amount_msats ( 10_000_000 )
1397+ . build ( ) . unwrap ( ) ;
1398+ assert_ne ! ( offer. signing_pubkey( ) , Some ( alice_id) ) ;
1399+ assert ! ( !offer. paths( ) . is_empty( ) ) ;
1400+ for path in offer. paths ( ) {
1401+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( bob_id) ) ;
1402+ }
1403+
1404+ // Initiate an invoice request, but abandon tracking it.
1405+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1406+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
1407+ . unwrap ( ) ;
1408+ david. node . abandon_payment ( payment_id) ;
1409+ get_event ! ( david, Event :: InvoiceRequestFailed ) ;
1410+
1411+ // Don't send the invoice request, but grab its reply path to use with a different request.
1412+ let invalid_reply_path = {
1413+ let mut pending_offers_messages = david. node . pending_offers_messages . lock ( ) . unwrap ( ) ;
1414+ let pending_invoice_request = pending_offers_messages. pop ( ) . unwrap ( ) ;
1415+ pending_offers_messages. clear ( ) ;
1416+ #[ cfg( not( c_bindings) ) ] {
1417+ pending_invoice_request. reply_path
1418+ }
1419+ #[ cfg( c_bindings) ] {
1420+ pending_invoice_request. 2
1421+ }
1422+ } ;
1423+
1424+ let payment_id = PaymentId ( [ 2 ; 32 ] ) ;
1425+ david. node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None )
1426+ . unwrap ( ) ;
1427+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1428+
1429+ // Swap out the reply path to force authentication to fail when handling the invoice since it
1430+ // will be sent over the wrong blinded path.
1431+ {
1432+ let mut pending_offers_messages = david. node . pending_offers_messages . lock ( ) . unwrap ( ) ;
1433+ let mut pending_invoice_request = pending_offers_messages. first_mut ( ) . unwrap ( ) ;
1434+ #[ cfg( not( c_bindings) ) ] {
1435+ pending_invoice_request. reply_path = invalid_reply_path;
1436+ }
1437+ #[ cfg( c_bindings) ] {
1438+ pending_invoice_request. 2 = invalid_reply_path;
1439+ }
1440+ }
1441+
1442+ connect_peers ( david, bob) ;
1443+
1444+ let onion_message = david. onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
1445+ bob. onion_messenger . handle_onion_message ( & david_id, & onion_message) ;
1446+
1447+ connect_peers ( alice, charlie) ;
1448+
1449+ let onion_message = bob. onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
1450+ alice. onion_messenger . handle_onion_message ( & bob_id, & onion_message) ;
1451+
1452+ let ( invoice_request, reply_path) = extract_invoice_request ( alice, & onion_message) ;
1453+ assert_eq ! ( invoice_request. amount_msats( ) , None ) ;
1454+ assert_ne ! ( invoice_request. payer_id( ) , david_id) ;
1455+ assert_eq ! ( reply_path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1456+
1457+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( charlie_id) . unwrap ( ) ;
1458+ charlie. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
1459+
1460+ let onion_message = charlie. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
1461+ david. onion_messenger . handle_onion_message ( & charlie_id, & onion_message) ;
1462+
1463+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1464+ }
1465+
1466+ /// Check that authentication fails when an invoice is handled using the wrong context (i.e., was
1467+ /// sent directly or over an unexpected blinded path).
1468+ #[ test]
1469+ fn fails_authentication_when_handling_invoice_for_refund ( ) {
1470+ let mut accept_forward_cfg = test_default_channel_config ( ) ;
1471+ accept_forward_cfg. accept_forwards_to_priv_channels = true ;
1472+
1473+ let mut features = channelmanager:: provided_init_features ( & accept_forward_cfg) ;
1474+ features. set_onion_messages_optional ( ) ;
1475+ features. set_route_blinding_optional ( ) ;
1476+
1477+ let chanmon_cfgs = create_chanmon_cfgs ( 6 ) ;
1478+ let node_cfgs = create_node_cfgs ( 6 , & chanmon_cfgs) ;
1479+
1480+ * node_cfgs[ 1 ] . override_init_features . borrow_mut ( ) = Some ( features) ;
1481+
1482+ let node_chanmgrs = create_node_chanmgrs (
1483+ 6 , & node_cfgs, & [ None , Some ( accept_forward_cfg) , None , None , None , None ]
1484+ ) ;
1485+ let nodes = create_network ( 6 , & node_cfgs, & node_chanmgrs) ;
1486+
1487+ create_unannounced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) ;
1488+ create_unannounced_chan_between_nodes_with_value ( & nodes, 2 , 3 , 10_000_000 , 1_000_000_000 ) ;
1489+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 2 , 10_000_000 , 1_000_000_000 ) ;
1490+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 4 , 10_000_000 , 1_000_000_000 ) ;
1491+ create_announced_chan_between_nodes_with_value ( & nodes, 1 , 5 , 10_000_000 , 1_000_000_000 ) ;
1492+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 4 , 10_000_000 , 1_000_000_000 ) ;
1493+ create_announced_chan_between_nodes_with_value ( & nodes, 2 , 5 , 10_000_000 , 1_000_000_000 ) ;
1494+
1495+ let ( alice, bob, charlie, david) = ( & nodes[ 0 ] , & nodes[ 1 ] , & nodes[ 2 ] , & nodes[ 3 ] ) ;
1496+ let alice_id = alice. node . get_our_node_id ( ) ;
1497+ let charlie_id = charlie. node . get_our_node_id ( ) ;
1498+ let david_id = david. node . get_our_node_id ( ) ;
1499+
1500+ disconnect_peers ( alice, & [ charlie, david, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1501+ disconnect_peers ( david, & [ bob, & nodes[ 4 ] , & nodes[ 5 ] ] ) ;
1502+
1503+ let absolute_expiry = Duration :: from_secs ( u64:: MAX ) ;
1504+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
1505+ let refund = david. node
1506+ . create_refund_builder ( 10_000_000 , absolute_expiry, payment_id, Retry :: Attempts ( 0 ) , None )
1507+ . unwrap ( )
1508+ . build ( ) . unwrap ( ) ;
1509+ assert_ne ! ( refund. payer_id( ) , david_id) ;
1510+ assert ! ( !refund. paths( ) . is_empty( ) ) ;
1511+ for path in refund. paths ( ) {
1512+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1513+ }
1514+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1515+
1516+ // Send the invoice directly to David instead of using a blinded path.
1517+ let expected_invoice = alice. node . request_refund_payment ( & refund) . unwrap ( ) ;
1518+
1519+ connect_peers ( david, alice) ;
1520+ #[ cfg( not( c_bindings) ) ] {
1521+ alice. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1522+ Destination :: Node ( david_id) ;
1523+ }
1524+ #[ cfg( c_bindings) ] {
1525+ alice. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . 1 =
1526+ Destination :: Node ( david_id) ;
1527+ }
1528+
1529+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
1530+ david. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
1531+
1532+ let ( invoice, _) = extract_invoice ( david, & onion_message) ;
1533+ assert_eq ! ( invoice, expected_invoice) ;
1534+
1535+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1536+ david. node . abandon_payment ( payment_id) ;
1537+ get_event ! ( david, Event :: InvoiceRequestFailed ) ;
1538+
1539+ // Send the invoice to David using an invalid blinded path.
1540+ let invalid_path = refund. paths ( ) . first ( ) . unwrap ( ) . clone ( ) ;
1541+ let payment_id = PaymentId ( [ 2 ; 32 ] ) ;
1542+ let refund = david. node
1543+ . create_refund_builder ( 10_000_000 , absolute_expiry, payment_id, Retry :: Attempts ( 0 ) , None )
1544+ . unwrap ( )
1545+ . build ( ) . unwrap ( ) ;
1546+ assert_ne ! ( refund. payer_id( ) , david_id) ;
1547+ assert ! ( !refund. paths( ) . is_empty( ) ) ;
1548+ for path in refund. paths ( ) {
1549+ assert_eq ! ( path. introduction_node, IntroductionNode :: NodeId ( charlie_id) ) ;
1550+ }
1551+
1552+ let expected_invoice = alice. node . request_refund_payment ( & refund) . unwrap ( ) ;
1553+
1554+ #[ cfg( not( c_bindings) ) ] {
1555+ alice. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . destination =
1556+ Destination :: BlindedPath ( invalid_path) ;
1557+ }
1558+ #[ cfg( c_bindings) ] {
1559+ alice. node . pending_offers_messages . lock ( ) . unwrap ( ) . first_mut ( ) . unwrap ( ) . 1 =
1560+ Destination :: BlindedPath ( invalid_path) ;
1561+ }
1562+
1563+ connect_peers ( alice, charlie) ;
1564+
1565+ let onion_message = alice. onion_messenger . next_onion_message_for_peer ( charlie_id) . unwrap ( ) ;
1566+ charlie. onion_messenger . handle_onion_message ( & alice_id, & onion_message) ;
1567+
1568+ let onion_message = charlie. onion_messenger . next_onion_message_for_peer ( david_id) . unwrap ( ) ;
1569+ david. onion_messenger . handle_onion_message ( & charlie_id, & onion_message) ;
1570+
1571+ let ( invoice, _) = extract_invoice ( david, & onion_message) ;
1572+ assert_eq ! ( invoice, expected_invoice) ;
1573+
1574+ expect_recent_payment ! ( david, RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
1575+ }
1576+
12371577/// Fails creating or paying an offer when a blinded path cannot be created because no peers are
12381578/// connected.
12391579#[ test]
0 commit comments