diff --git a/vendor/manifest b/vendor/manifest index 9200690e8..5bd25a50e 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -116,7 +116,7 @@ { "importpath": "github.com/matrix-org/gomatrixserverlib", "repository": "https://github.com/matrix-org/gomatrixserverlib", - "revision": "ce6f4766251e31487906dfaaebd7d7cfea147252", + "revision": "f3be4cb492f23eb30a9f2ab5fc5bd85ee9c3add6", "branch": "master" }, { diff --git a/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go b/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go index 71c065603..2a26e7af9 100644 --- a/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go +++ b/vendor/src/github.com/matrix-org/gomatrixserverlib/event.go @@ -389,6 +389,8 @@ func (e Event) CheckFields() error { // nolint: gocyclo return err } + origin := e.fields.Origin + senderDomain, err := checkID(e.fields.Sender, "user", '@') if err != nil { return err @@ -406,34 +408,33 @@ func (e Event) CheckFields() error { // nolint: gocyclo // Since both domains must be valid domains, and there is no good reason for them // to be different we might as well ensure that they are the same since it // makes the signature checks simpler. - if e.fields.Origin != ServerName(eventDomain) { + if origin != ServerName(eventDomain) { return fmt.Errorf( "gomatrixserverlib: event ID domain doesn't match origin: %q != %q", - eventDomain, e.fields.Origin, + eventDomain, origin, ) } - if eventDomain != senderDomain { + if origin != ServerName(senderDomain) { // For the most part all events should be sent by a user on the - // originating server + // originating server. + // // However "m.room.member" events created from third-party invites // are allowed to have a different sender because they have the same // sender as the "m.room.third_party_invite" event they derived from. // https://github.com/matrix-org/synapse/blob/v0.21.0/synapse/event_auth.py#L58-L64 + // + // Also, some old versions of synapse had a bug wherein some + // joins/leaves used the origin and event id supplied by the helping + // server instead of the joining/leaving server. + // + // So in general we allow the sender to be different from the + // origin for m.room.member events. In any case, we check it was + // signed by both servers later. if e.fields.Type != MRoomMember { return fmt.Errorf( "gomatrixserverlib: sender domain doesn't match origin: %q != %q", - senderDomain, e.fields.Origin, - ) - } - c, err := newMemberContentFromEvent(e) - if err != nil { - return err - } - if c.Membership != invite || c.ThirdPartyInvite == nil { - return fmt.Errorf( - "gomatrixserverlib: sender domain doesn't match origin: %q != %q", - senderDomain, e.fields.Origin, + senderDomain, origin, ) } } diff --git a/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto.go b/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto.go index 7d5f417c9..255b269d4 100644 --- a/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto.go +++ b/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto.go @@ -189,19 +189,33 @@ func verifyEventSignature(signingName string, keyID KeyID, publicKey ed25519.Pub // VerifyEventSignatures checks that each event in a list of events has valid // signatures from the server that sent it. -func VerifyEventSignatures(ctx context.Context, events []Event, keyRing KeyRing) error { // nolint: gocyclo +func VerifyEventSignatures(ctx context.Context, events []Event, keyRing JSONVerifier) error { // nolint: gocyclo var toVerify []VerifyJSONRequest for _, event := range events { redactedJSON, err := redactEvent(event.eventJSON) if err != nil { return err } - v := VerifyJSONRequest{ - Message: redactedJSON, - AtTS: event.OriginServerTS(), - ServerName: event.Origin(), + + domains := make(map[ServerName]bool) + domains[event.Origin()] = true + + // in general, we expect the domain of the sender id to be the + // same as the origin; however there was a bug in an old version + // of synapse which meant that some joins/leaves used the origin + // and event id supplied by the helping server instead of the + // joining/leaving server. + // + // That's ok, provided it's signed by the sender's server too. + // + // XXX we may have to exclude 3pid invites here, as per + // https://github.com/matrix-org/synapse/blob/v0.21.0/synapse/event_auth.py#L58-L64. + // + senderDomain, err := domainFromID(event.Sender()) + if err != nil { + return err } - toVerify = append(toVerify, v) + domains[ServerName(senderDomain)] = true // MRoomMember invite events are signed by both the server sending // the invite and the server the invite is for. @@ -216,11 +230,19 @@ func VerifyEventSignatures(ctx context.Context, events []Event, keyRing KeyRing) return err } if c.Membership == invite { - v.ServerName = ServerName(targetDomain) - toVerify = append(toVerify, v) + domains[ServerName(targetDomain)] = true } } } + + for domain := range domains { + v := VerifyJSONRequest{ + Message: redactedJSON, + AtTS: event.OriginServerTS(), + ServerName: domain, + } + toVerify = append(toVerify, v) + } } results, err := keyRing.VerifyJSONs(ctx, toVerify) diff --git a/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto_test.go b/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto_test.go index f97d0c1d4..72d868818 100644 --- a/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto_test.go +++ b/vendor/src/github.com/matrix-org/gomatrixserverlib/eventcrypto_test.go @@ -17,7 +17,10 @@ package gomatrixserverlib import ( "bytes" + "context" "encoding/base64" + "encoding/json" + "sort" "testing" "golang.org/x/crypto/ed25519" @@ -258,3 +261,127 @@ func TestSignEventTestVectors(t *testing.T) { } }`) } + +type StubVerifier struct { + requests []VerifyJSONRequest + results []VerifyJSONResult +} + +func (v *StubVerifier) VerifyJSONs(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error) { + v.requests = append(v.requests, requests...) + return v.results, nil +} + +func TestVerifyEventSignatures(t *testing.T) { + verifier := StubVerifier{} + + eventJSON := []byte(`{ + "type": "m.room.name", + "state_key": "", + "event_id": "$test:localhost", + "room_id": "!test:localhost", + "sender": "@test:localhost", + "origin": "originserver", + "content": { + "name": "Hello World" + }, + "origin_server_ts": 123456 + }`) + + var event Event + if err := json.Unmarshal(eventJSON, &event.fields); err != nil { + t.Fatal(err) + } + event.eventJSON = eventJSON + + events := []Event{event} + if err := VerifyEventSignatures(context.Background(), events, &verifier); err != nil { + t.Fatal(err) + } + + // There should be two verification requests + if len(verifier.requests) != 2 { + t.Fatalf("Number of requests: got %d, want 2", len(verifier.requests)) + } + wantContent, err := redactEvent(eventJSON) + if err != nil { + t.Fatal(err) + } + + servers := []string{} + + for i, rq := range verifier.requests { + if !bytes.Equal(rq.Message, wantContent) { + t.Errorf("Verify content %d: got %s, want %s", i, rq.Message, wantContent) + } + if rq.AtTS != 123456 { + t.Errorf("Verify time %d: got %d, want %d", i, rq.AtTS, 123456) + } + servers = append(servers, string(rq.ServerName)) + } + + sort.Strings(servers) + if servers[0] != "localhost" { + t.Errorf("Verify server 0: got %s, want %s", servers[0], "localhost") + } + if servers[1] != "originserver" { + t.Errorf("Verify server 1: got %s, want %s", servers[1], "originserver") + } +} + +func TestVerifyEventSignaturesForInvite(t *testing.T) { + verifier := StubVerifier{} + + eventJSON := []byte(`{ + "type": "m.room.member", + "state_key": "@bob:bobserver", + "event_id": "$test:aliceserver", + "room_id": "!test:room", + "sender": "@alice:aliceserver", + "origin": "aliceserver", + "content": { + "membership": "invite" + }, + "origin_server_ts": 123456 + }`) + + var event Event + if err := json.Unmarshal(eventJSON, &event.fields); err != nil { + t.Fatal(err) + } + event.eventJSON = eventJSON + + events := []Event{event} + if err := VerifyEventSignatures(context.Background(), events, &verifier); err != nil { + t.Fatal(err) + } + + // There should be two verification requests + if len(verifier.requests) != 2 { + t.Fatalf("Number of requests: got %d, want 2", len(verifier.requests)) + } + wantContent, err := redactEvent(eventJSON) + if err != nil { + t.Fatal(err) + } + + servers := []string{} + + for i, rq := range verifier.requests { + if !bytes.Equal(rq.Message, wantContent) { + t.Errorf("Verify content %d: got %s, want %s", i, rq.Message, wantContent) + } + if rq.AtTS != 123456 { + t.Errorf("Verify time %d: got %d, want %d", i, rq.AtTS, 123456) + } + servers = append(servers, string(rq.ServerName)) + } + + sort.Strings(servers) + if servers[0] != "aliceserver" { + t.Errorf("Verify server 0: got %s, want %s", servers[0], "aliceserver") + } + if servers[1] != "bobserver" { + t.Errorf("Verify server 1: got %s, want %s", servers[1], "bobserver") + } +} diff --git a/vendor/src/github.com/matrix-org/gomatrixserverlib/federationtypes.go b/vendor/src/github.com/matrix-org/gomatrixserverlib/federationtypes.go index 58c46ce24..d4cfab867 100644 --- a/vendor/src/github.com/matrix-org/gomatrixserverlib/federationtypes.go +++ b/vendor/src/github.com/matrix-org/gomatrixserverlib/federationtypes.go @@ -108,7 +108,7 @@ func (r RespState) Events() ([]Event, error) { } // Check that a response to /state is valid. -func (r RespState) Check(ctx context.Context, keyRing KeyRing) error { +func (r RespState) Check(ctx context.Context, keyRing JSONVerifier) error { var allEvents []Event for _, event := range r.AuthEvents { if event.StateKey() == nil { @@ -214,8 +214,10 @@ type respSendJoinFields struct { // Check that a response to /send_join is valid. // This checks that it would be valid as a response to /state // This also checks that the join event is allowed by the state. -func (r RespSendJoin) Check(ctx context.Context, keyRing KeyRing, joinEvent Event) error { - // First check that the state is valid. +func (r RespSendJoin) Check(ctx context.Context, keyRing JSONVerifier, joinEvent Event) error { + // First check that the state is valid and that the events in the response + // are correctly signed. + // // The response to /send_join has the same data as a response to /state // and the checks for a response to /state also apply. if err := RespState(r).Check(ctx, keyRing); err != nil { diff --git a/vendor/src/github.com/matrix-org/gomatrixserverlib/keyring.go b/vendor/src/github.com/matrix-org/gomatrixserverlib/keyring.go index 954fc2595..324e59d13 100644 --- a/vendor/src/github.com/matrix-org/gomatrixserverlib/keyring.go +++ b/vendor/src/github.com/matrix-org/gomatrixserverlib/keyring.go @@ -69,12 +69,18 @@ type VerifyJSONResult struct { Error error } -// VerifyJSONs performs bulk JSON signature verification for a list of VerifyJSONRequests. -// Returns a list of VerifyJSONResults with the same length and order as the request list. -// The caller should check the Result field for each entry to see if it was valid. -// Returns an error if there was a problem talking to the database or one of the other methods -// of fetching the public keys. -func (k *KeyRing) VerifyJSONs(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error) { // nolint: gocyclo +// A JSONVerifier is an object which can verify the signatures of JSON messages. +type JSONVerifier interface { + // VerifyJSONs performs bulk JSON signature verification for a list of VerifyJSONRequests. + // Returns a list of VerifyJSONResults with the same length and order as the request list. + // The caller should check the Result field for each entry to see if it was valid. + // Returns an error if there was a problem talking to the database or one of the other methods + // of fetching the public keys. + VerifyJSONs(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error) +} + +// VerifyJSONs implements JSONVerifier. +func (k KeyRing) VerifyJSONs(ctx context.Context, requests []VerifyJSONRequest) ([]VerifyJSONResult, error) { // nolint: gocyclo results := make([]VerifyJSONResult, len(requests)) keyIDs := make([][]KeyID, len(requests)) diff --git a/vendor/src/github.com/matrix-org/gomatrixserverlib/request.go b/vendor/src/github.com/matrix-org/gomatrixserverlib/request.go index 84874ebe0..b7872cbea 100644 --- a/vendor/src/github.com/matrix-org/gomatrixserverlib/request.go +++ b/vendor/src/github.com/matrix-org/gomatrixserverlib/request.go @@ -184,7 +184,7 @@ func isSafeInHTTPQuotedString(text string) bool { // nolint: gocyclo // It consumes the body of the request. // The JSON content can be accessed using FederationRequest.Content() // Returns an 400 error if there was a problem parsing the request. -// It authenticates the request using an ed25519 signature using the KeyRing. +// It authenticates the request using an ed25519 signature using the JSONVerifier. // The origin server can be accessed using FederationRequest.Origin() // Returns a 401 error if there was a problem authenticating the request. // HTTP handlers using this should be careful that they only use the parts of @@ -192,7 +192,7 @@ func isSafeInHTTPQuotedString(text string) bool { // nolint: gocyclo // the query parameters, and the JSON content. In particular the version of // HTTP and the headers aren't protected by the signature. func VerifyHTTPRequest( - req *http.Request, now time.Time, destination ServerName, keys KeyRing, + req *http.Request, now time.Time, destination ServerName, keys JSONVerifier, ) (*FederationRequest, util.JSONResponse) { request, err := readHTTPRequest(req) if err != nil {