@@ -54,7 +54,7 @@ use crate::offers::invoice::Bolt12Invoice;
54
54
use crate :: offers:: invoice_error:: InvoiceError ;
55
55
use crate :: offers:: invoice_request:: { InvoiceRequest , InvoiceRequestFields } ;
56
56
use crate :: offers:: parse:: Bolt12SemanticError ;
57
- use crate :: onion_message:: messenger:: PeeledOnion ;
57
+ use crate :: onion_message:: messenger:: { Destination , PeeledOnion } ;
58
58
use crate :: onion_message:: offers:: OffersMessage ;
59
59
use crate :: onion_message:: packet:: ParsedOnionMessageContents ;
60
60
use crate :: routing:: gossip:: { NodeAlias , NodeId } ;
@@ -1234,6 +1234,346 @@ fn creates_refund_with_blinded_path_using_unannounced_introduction_node() {
1234
1234
}
1235
1235
}
1236
1236
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
+
1237
1577
/// Fails creating or paying an offer when a blinded path cannot be created because no peers are
1238
1578
/// connected.
1239
1579
#[ test]
0 commit comments