From f53f5dc7f634c1781f2c92ca37b8e9e020b0e9f1 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 22 Oct 2021 11:25:46 +0100 Subject: [PATCH 1/3] Test for send_join with unverifiable auth events Test the behaviour when we send a `send_join` response with unverifiable auth events --- tests/federation_room_join_test.go | 61 +++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 2 deletions(-) diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 4905ad39..2c00a1de 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -88,9 +88,11 @@ func TestJoinViaRoomIDAndServerName(t *testing.T) { // - Events with missing signatures // - Events with bad signatures // - Events with correct signatures but the keys cannot be obtained +// - State events whose auth events cannot be verified +// // None of these events will be critical to the integrity of the room: that -// is to say these events are never pointed to as auth_events - therefore the -// room should still be joinable. +// is to say these events are not used as auth_events for the actual join - +// therefore the room should still be joinable. // // This test works by creating several federated rooms on Complement which have // the properties listed above, then asking HS1 to join them and make sure that @@ -162,6 +164,7 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { unsignedEvent, err := gomatrixserverlib.NewEventFromTrustedJSON(raw, false, ver) must.NotError(t, "failed to make Event from unsigned event JSON", err) room.AddEvent(unsignedEvent) + alice := deployment.Client(t, "hs1", "@alice:hs1") alice.JoinRoom(t, roomAlias, nil) }) @@ -195,6 +198,60 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { alice := deployment.Client(t, "hs1", "@alice:hs1") alice.JoinRoom(t, roomAlias, nil) }) + t.Run("/send_join response with state with unverifiable auth events shouldn't block room join", func(t *testing.T) { + //t.Parallel() + room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie)) + roomAlias := srv.MakeAliasMapping("UnverifiableAuthEvents", room.RoomID) + + // create a normal event then modify the signatures + rawEvent := srv.MustCreateEvent(t, room, b.Event{ + Sender: charlie, + StateKey: &charlie, + Type: "m.room.member", + Content: map[string]interface{}{ + "membership": "join", + "name": "This event has a bad signature", + }, + }).JSON() + rawSig, err := json.Marshal(map[string]interface{}{ + docker.HostnameRunningComplement: map[string]string{ + string(srv.KeyID): "/3z+pJjiJXWhwfqIEzmNksvBHCoXTktK/y0rRuWJXw6i1+ygRG/suDCKhFuuz6gPapRmEMPVILi2mJqHHXPKAg", + }, + }) + must.NotError(t, "failed to marshal bad signature block", err) + rawEvent, err = sjson.SetRawBytes(rawEvent, "signatures", rawSig) + must.NotError(t, "failed to modify signatures key from event", err) + badlySignedEvent, err := gomatrixserverlib.NewEventFromTrustedJSON(rawEvent, false, ver) + must.NotError(t, "failed to make Event from badly signed event JSON", err) + room.AddEvent(badlySignedEvent) + t.Logf("Created badly signed auth event %s", badlySignedEvent.EventID()) + + // and now add another event which will use it as an auth event. + goodEvent := srv.MustCreateEvent(t, room, b.Event{ + Sender: charlie, + StateKey: &charlie, + Type: "m.room.member", + Content: map[string]interface{}{ + "membership": "leave", + }, + }) + // double-check that the bad event is in its auth events + containsEvent := false + for _, authEventID := range goodEvent.AuthEventIDs() { + if authEventID == badlySignedEvent.EventID() { + containsEvent = true + break + } + } + if !containsEvent { + t.Fatalf("Bad event didn't appear in auth events of state event") + } + room.AddEvent(goodEvent) + t.Logf("Created state event %s", goodEvent.EventID()) + + alice := deployment.Client(t, "hs1", "@alice:hs1") + alice.JoinRoom(t, roomAlias, nil) + }) } // This test checks that users cannot circumvent the auth checks via send_join. From 67e825c6ae05f5e4f62240b67bf458e088351a86 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 22 Oct 2021 15:15:05 +0100 Subject: [PATCH 2/3] move test to its own file ... to allow blacklisting for dendrite --- tests/federation_room_join_test.go | 54 ----------- ...join_with_unverifiable_auth_events_test.go | 91 +++++++++++++++++++ 2 files changed, 91 insertions(+), 54 deletions(-) create mode 100644 tests/federation_room_join_with_unverifiable_auth_events_test.go diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 2c00a1de..778f9209 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -198,60 +198,6 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { alice := deployment.Client(t, "hs1", "@alice:hs1") alice.JoinRoom(t, roomAlias, nil) }) - t.Run("/send_join response with state with unverifiable auth events shouldn't block room join", func(t *testing.T) { - //t.Parallel() - room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie)) - roomAlias := srv.MakeAliasMapping("UnverifiableAuthEvents", room.RoomID) - - // create a normal event then modify the signatures - rawEvent := srv.MustCreateEvent(t, room, b.Event{ - Sender: charlie, - StateKey: &charlie, - Type: "m.room.member", - Content: map[string]interface{}{ - "membership": "join", - "name": "This event has a bad signature", - }, - }).JSON() - rawSig, err := json.Marshal(map[string]interface{}{ - docker.HostnameRunningComplement: map[string]string{ - string(srv.KeyID): "/3z+pJjiJXWhwfqIEzmNksvBHCoXTktK/y0rRuWJXw6i1+ygRG/suDCKhFuuz6gPapRmEMPVILi2mJqHHXPKAg", - }, - }) - must.NotError(t, "failed to marshal bad signature block", err) - rawEvent, err = sjson.SetRawBytes(rawEvent, "signatures", rawSig) - must.NotError(t, "failed to modify signatures key from event", err) - badlySignedEvent, err := gomatrixserverlib.NewEventFromTrustedJSON(rawEvent, false, ver) - must.NotError(t, "failed to make Event from badly signed event JSON", err) - room.AddEvent(badlySignedEvent) - t.Logf("Created badly signed auth event %s", badlySignedEvent.EventID()) - - // and now add another event which will use it as an auth event. - goodEvent := srv.MustCreateEvent(t, room, b.Event{ - Sender: charlie, - StateKey: &charlie, - Type: "m.room.member", - Content: map[string]interface{}{ - "membership": "leave", - }, - }) - // double-check that the bad event is in its auth events - containsEvent := false - for _, authEventID := range goodEvent.AuthEventIDs() { - if authEventID == badlySignedEvent.EventID() { - containsEvent = true - break - } - } - if !containsEvent { - t.Fatalf("Bad event didn't appear in auth events of state event") - } - room.AddEvent(goodEvent) - t.Logf("Created state event %s", goodEvent.EventID()) - - alice := deployment.Client(t, "hs1", "@alice:hs1") - alice.JoinRoom(t, roomAlias, nil) - }) } // This test checks that users cannot circumvent the auth checks via send_join. diff --git a/tests/federation_room_join_with_unverifiable_auth_events_test.go b/tests/federation_room_join_with_unverifiable_auth_events_test.go new file mode 100644 index 00000000..6868b548 --- /dev/null +++ b/tests/federation_room_join_with_unverifiable_auth_events_test.go @@ -0,0 +1,91 @@ +// +build !dendrite_blacklist + +package tests + +import ( + "encoding/json" + "testing" + + "github.com/matrix-org/gomatrixserverlib" + "github.com/tidwall/sjson" + + "github.com/matrix-org/complement/internal/b" + "github.com/matrix-org/complement/internal/docker" + "github.com/matrix-org/complement/internal/federation" + "github.com/matrix-org/complement/internal/must" +) + +// This test is an extension of TestJoinFederatedRoomWithUnverifiableEvents. +// It's currently split out, because it fails on Dendrite +// - see https://github.com/matrix-org/dendrite/issues/2028 +func TestJoinFederatedRoomWithUnverifiableAuthEvents(t *testing.T) { + deployment := Deploy(t, b.BlueprintAlice) + defer deployment.Destroy(t) + + srv := federation.NewServer(t, deployment, + federation.HandleKeyRequests(), + federation.HandleMakeSendJoinRequests(), + federation.HandleTransactionRequests(nil, nil), + ) + srv.UnexpectedRequestsAreErrors = false + cancel := srv.Listen() + defer cancel() + + ver := gomatrixserverlib.RoomVersionV6 + charlie := srv.UserID("charlie") + + t.Run("/send_join response with state with unverifiable auth events shouldn't block room join", func(t *testing.T) { + //t.Parallel() + room := srv.MustMakeRoom(t, ver, federation.InitialRoomEvents(ver, charlie)) + roomAlias := srv.MakeAliasMapping("UnverifiableAuthEvents", room.RoomID) + + // create a normal event then modify the signatures + rawEvent := srv.MustCreateEvent(t, room, b.Event{ + Sender: charlie, + StateKey: &charlie, + Type: "m.room.member", + Content: map[string]interface{}{ + "membership": "join", + "name": "This event has a bad signature", + }, + }).JSON() + rawSig, err := json.Marshal(map[string]interface{}{ + docker.HostnameRunningComplement: map[string]string{ + string(srv.KeyID): "/3z+pJjiJXWhwfqIEzmNksvBHCoXTktK/y0rRuWJXw6i1+ygRG/suDCKhFuuz6gPapRmEMPVILi2mJqHHXPKAg", + }, + }) + must.NotError(t, "failed to marshal bad signature block", err) + rawEvent, err = sjson.SetRawBytes(rawEvent, "signatures", rawSig) + must.NotError(t, "failed to modify signatures key from event", err) + badlySignedEvent, err := gomatrixserverlib.NewEventFromTrustedJSON(rawEvent, false, ver) + must.NotError(t, "failed to make Event from badly signed event JSON", err) + room.AddEvent(badlySignedEvent) + t.Logf("Created badly signed auth event %s", badlySignedEvent.EventID()) + + // and now add another event which will use it as an auth event. + goodEvent := srv.MustCreateEvent(t, room, b.Event{ + Sender: charlie, + StateKey: &charlie, + Type: "m.room.member", + Content: map[string]interface{}{ + "membership": "leave", + }, + }) + // double-check that the bad event is in its auth events + containsEvent := false + for _, authEventID := range goodEvent.AuthEventIDs() { + if authEventID == badlySignedEvent.EventID() { + containsEvent = true + break + } + } + if !containsEvent { + t.Fatalf("Bad event didn't appear in auth events of state event") + } + room.AddEvent(goodEvent) + t.Logf("Created state event %s", goodEvent.EventID()) + + alice := deployment.Client(t, "hs1", "@alice:hs1") + alice.JoinRoom(t, roomAlias, nil) + }) +} From af88ac1c0709203ed889d75d54cdccba3227a120 Mon Sep 17 00:00:00 2001 From: Richard van der Hoff Date: Fri, 22 Oct 2021 15:26:42 +0100 Subject: [PATCH 3/3] minor diff cleanups --- tests/federation_room_join_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 778f9209..0e32bee5 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -88,7 +88,6 @@ func TestJoinViaRoomIDAndServerName(t *testing.T) { // - Events with missing signatures // - Events with bad signatures // - Events with correct signatures but the keys cannot be obtained -// - State events whose auth events cannot be verified // // None of these events will be critical to the integrity of the room: that // is to say these events are not used as auth_events for the actual join - @@ -164,7 +163,6 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { unsignedEvent, err := gomatrixserverlib.NewEventFromTrustedJSON(raw, false, ver) must.NotError(t, "failed to make Event from unsigned event JSON", err) room.AddEvent(unsignedEvent) - alice := deployment.Client(t, "hs1", "@alice:hs1") alice.JoinRoom(t, roomAlias, nil) })