|
9 | 9 | "fmt" |
10 | 10 | "math/big" |
11 | 11 | "reflect" |
| 12 | + "strings" |
12 | 13 | "testing" |
13 | 14 | "time" |
14 | 15 | "unsafe" |
@@ -469,18 +470,17 @@ func TestSessionManager_Integration(t *testing.T) { |
469 | 470 | Type: "setup", |
470 | 471 | EventID: event.EventID, |
471 | 472 | Participants: []string{"validator1", "validator2", "validator3"}, |
472 | | - Payload: []byte("invalid setup data"), // Will fail when creating session |
| 473 | + Payload: []byte("invalid setup data"), // rejected before a session is created |
473 | 474 | } |
474 | 475 |
|
475 | | - // This will fail at session creation or GetLatestBlockNum, but validation should pass |
| 476 | + // Rejected at the setup-binding check (the payload is not a decodable DKLS |
| 477 | + // setup), or earlier at GetLatestBlockNum. Either way validation must not |
| 478 | + // let an unbound payload reach session creation. |
476 | 479 | err := sm.HandleIncomingMessage(ctx, "peer1", &msg) |
477 | | - // We expect an error because we can't create a real DKLS session with invalid data |
478 | | - // or because GetLatestBlockNum fails |
479 | 480 | assert.Error(t, err) |
480 | | - // Error should be about session creation, DKLS library, or no endpoints |
481 | 481 | assert.True(t, |
482 | | - containsAny(err.Error(), []string{"failed to create session", "DKLS", "dkls", "session", "no endpoints"}), |
483 | | - "error should be about session creation or endpoints, got: %s", err.Error()) |
| 482 | + containsAny(err.Error(), []string{"failed to create session", "DKLS", "dkls", "session", "setup message", "no endpoints"}), |
| 483 | + "error should be about setup binding, session creation or endpoints, got: %s", err.Error()) |
484 | 484 | } |
485 | 485 |
|
486 | 486 | func TestVerifySigningRequest_OutboundDisabled(t *testing.T) { |
@@ -1496,3 +1496,51 @@ func TestVerifySetupBindsHash(t *testing.T) { |
1496 | 1496 | assert.Contains(t, err.Error(), "no verified signing hash") |
1497 | 1497 | }) |
1498 | 1498 | } |
| 1499 | + |
| 1500 | +// Keygen, keyrefresh and quorumchange have the same split as the sign path: we |
| 1501 | +// validate msg.Participants, but the session runs on the list embedded in |
| 1502 | +// Payload. The threshold cannot be bound this way, see verifySetupBindsParticipants. |
| 1503 | +func TestVerifySetupBindsParticipants(t *testing.T) { |
| 1504 | + validated := []string{"validator1", "validator2", "validator3"} |
| 1505 | + encode := func(ids []string) []byte { |
| 1506 | + return []byte(strings.Join(ids, "\x00")) |
| 1507 | + } |
| 1508 | + |
| 1509 | + legitSetup, err := session.DklsKeygenSetupMsgNew(2, nil, encode(validated)) |
| 1510 | + require.NoError(t, err) |
| 1511 | + |
| 1512 | + t.Run("accepts setup with the validated participants", func(t *testing.T) { |
| 1513 | + require.NoError(t, verifySetupBindsParticipants(legitSetup, validated)) |
| 1514 | + }) |
| 1515 | + |
| 1516 | + t.Run("rejects setup with a substituted participant", func(t *testing.T) { |
| 1517 | + swapped, err := session.DklsKeygenSetupMsgNew(2, nil, |
| 1518 | + encode([]string{"validator1", "validator2", "attacker"})) |
| 1519 | + require.NoError(t, err) |
| 1520 | + err = verifySetupBindsParticipants(swapped, validated) |
| 1521 | + require.Error(t, err) |
| 1522 | + assert.Contains(t, err.Error(), "do not match validated participants") |
| 1523 | + }) |
| 1524 | + |
| 1525 | + t.Run("rejects setup with a dropped participant", func(t *testing.T) { |
| 1526 | + fewer, err := session.DklsKeygenSetupMsgNew(2, nil, |
| 1527 | + encode([]string{"validator1", "validator2"})) |
| 1528 | + require.NoError(t, err) |
| 1529 | + require.Error(t, verifySetupBindsParticipants(fewer, validated)) |
| 1530 | + }) |
| 1531 | + |
| 1532 | + // Index order is part of the protocol, so a reorder is as consequential as |
| 1533 | + // a substitution. |
| 1534 | + t.Run("rejects reordered participants", func(t *testing.T) { |
| 1535 | + reordered, err := session.DklsKeygenSetupMsgNew(2, nil, |
| 1536 | + encode([]string{"validator3", "validator2", "validator1"})) |
| 1537 | + require.NoError(t, err) |
| 1538 | + require.Error(t, verifySetupBindsParticipants(reordered, validated)) |
| 1539 | + }) |
| 1540 | + |
| 1541 | + t.Run("rejects undecodable setup and missing validated list", func(t *testing.T) { |
| 1542 | + require.Error(t, verifySetupBindsParticipants([]byte("not-a-setup"), validated)) |
| 1543 | + require.Error(t, verifySetupBindsParticipants(nil, validated)) |
| 1544 | + require.Error(t, verifySetupBindsParticipants(legitSetup, nil)) |
| 1545 | + }) |
| 1546 | +} |
0 commit comments