From 8e5a0139b5eb3c02c8c2e65b2a6444616e813978 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Thu, 5 Aug 2021 11:48:22 +0100 Subject: [PATCH 1/3] Update to matrix-org/gomatrixserverlib@03e40fa --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 154bf8ca9..39f6020ce 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4 github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 - github.com/matrix-org/gomatrixserverlib v0.0.0-20210802144451-bec8d2252d83 + github.com/matrix-org/gomatrixserverlib v0.0.0-20210805104751-03e40fa2c0e1 github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0 github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 diff --git a/go.sum b/go.sum index 5c614c459..df5e2b857 100644 --- a/go.sum +++ b/go.sum @@ -994,8 +994,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d/go.mod h1 github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0= github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4= github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= -github.com/matrix-org/gomatrixserverlib v0.0.0-20210802144451-bec8d2252d83 h1:fkUmeKj/U5TnWXTsJnVjEL0FQiVhf1r9WL4VWI00q2k= -github.com/matrix-org/gomatrixserverlib v0.0.0-20210802144451-bec8d2252d83/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU= +github.com/matrix-org/gomatrixserverlib v0.0.0-20210805104751-03e40fa2c0e1 h1:ExS9AmOWYSZ4DR7W7Eqm7glP/g/u/CTVLAu9blAnve4= +github.com/matrix-org/gomatrixserverlib v0.0.0-20210805104751-03e40fa2c0e1/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU= github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0 h1:HZCzy4oVzz55e+cOMiX/JtSF2UOY1evBl2raaE7ACcU= github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0/go.mod h1:sjyPyRxKM5uw1nD2cJ6O2OxI6GOqyVBfNXqKjBZTBZE= github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b h1:5X5vdWQ13xrNkJVqaJHPsrt7rKkMJH5iac0EtfOuxSg= From e95b1fd2383d29dbce8831f5588e7e3df064af31 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Fri, 6 Aug 2021 10:13:35 +0100 Subject: [PATCH 2/3] Cross-signing validation for self-sigs, expose signatures over `/user/keys/query` and `/user/devices/{userId}` (#1962) * Enable unstable feature again * Try to verify when a device signs a key * Try to verify when a key signs a device * It's the self-signing key, not the master key * Fix error * Try to verify master key uploads * Actually we can't guarantee we can do that so nevermind * Add signatures into /devices/list request * Fix nil pointer * Reprioritise map creation * Don't skip devices that don't have signatures * Add some debug logging * Fix logic error in QuerySignatures * Fix bugs * Expose master and self-signing keys on /devices/list hopefully * maps are tedious * Expose signatures via /keys/query * Upload signatures when uploading keys * Fixes * Disable the feature again --- federationapi/routing/devices.go | 30 ++++ keyserver/api/api.go | 20 +++ keyserver/internal/cross_signing.go | 219 ++++++++++++++++++++++++---- keyserver/internal/internal.go | 34 ++++- keyserver/inthttp/client.go | 18 +++ keyserver/inthttp/server.go | 11 ++ keyserver/storage/interface.go | 3 +- keyserver/storage/shared/storage.go | 41 +++++- syncapi/internal/keychange_test.go | 2 + 9 files changed, 341 insertions(+), 37 deletions(-) diff --git a/federationapi/routing/devices.go b/federationapi/routing/devices.go index 07862451f..b397c5460 100644 --- a/federationapi/routing/devices.go +++ b/federationapi/routing/devices.go @@ -37,12 +37,28 @@ func GetUserDevices( return jsonerror.InternalServerError() } + sigReq := &keyapi.QuerySignaturesRequest{ + TargetIDs: map[string][]gomatrixserverlib.KeyID{}, + } + sigRes := &keyapi.QuerySignaturesResponse{} + for _, dev := range res.Devices { + sigReq.TargetIDs[userID] = append(sigReq.TargetIDs[userID], gomatrixserverlib.KeyID(dev.DeviceID)) + } + keyAPI.QuerySignatures(req.Context(), sigReq, sigRes) + response := gomatrixserverlib.RespUserDevices{ UserID: userID, StreamID: res.StreamID, Devices: []gomatrixserverlib.RespUserDevice{}, } + if masterKey, ok := sigRes.MasterKeys[userID]; ok { + response.MasterKey = &masterKey + } + if selfSigningKey, ok := sigRes.SelfSigningKeys[userID]; ok { + response.SelfSigningKey = &selfSigningKey + } + for _, dev := range res.Devices { var key gomatrixserverlib.RespUserDeviceKeys err := json.Unmarshal(dev.DeviceKeys.KeyJSON, &key) @@ -56,6 +72,20 @@ func GetUserDevices( DisplayName: dev.DisplayName, Keys: key, } + + if targetUser, ok := sigRes.Signatures[userID]; ok { + if targetKey, ok := targetUser[gomatrixserverlib.KeyID(dev.DeviceID)]; ok { + for sourceUserID, forSourceUser := range targetKey { + for sourceKeyID, sourceKey := range forSourceUser { + if _, ok := device.Keys.Signatures[sourceUserID]; !ok { + device.Keys.Signatures[sourceUserID] = map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{} + } + device.Keys.Signatures[sourceUserID][sourceKeyID] = sourceKey + } + } + } + } + response.Devices = append(response.Devices, device) } diff --git a/keyserver/api/api.go b/keyserver/api/api.go index f46a9ee26..520562e7a 100644 --- a/keyserver/api/api.go +++ b/keyserver/api/api.go @@ -20,6 +20,7 @@ import ( "strings" "time" + "github.com/matrix-org/dendrite/keyserver/types" userapi "github.com/matrix-org/dendrite/userapi/api" "github.com/matrix-org/gomatrixserverlib" ) @@ -38,6 +39,7 @@ type KeyInternalAPI interface { QueryKeyChanges(ctx context.Context, req *QueryKeyChangesRequest, res *QueryKeyChangesResponse) QueryOneTimeKeys(ctx context.Context, req *QueryOneTimeKeysRequest, res *QueryOneTimeKeysResponse) QueryDeviceMessages(ctx context.Context, req *QueryDeviceMessagesRequest, res *QueryDeviceMessagesResponse) + QuerySignatures(ctx context.Context, req *QuerySignaturesRequest, res *QuerySignaturesResponse) } // KeyError is returned if there was a problem performing/querying the server @@ -242,6 +244,24 @@ type QueryDeviceMessagesResponse struct { Error *KeyError } +type QuerySignaturesRequest struct { + // A map of target user ID -> target key/device IDs to retrieve signatures for + TargetIDs map[string][]gomatrixserverlib.KeyID `json:"target_ids"` +} + +type QuerySignaturesResponse struct { + // A map of target user ID -> target key/device ID -> origin user ID -> origin key/device ID -> signatures + Signatures map[string]map[gomatrixserverlib.KeyID]types.CrossSigningSigMap + // A map of target user ID -> cross-signing master key + MasterKeys map[string]gomatrixserverlib.CrossSigningKey + // A map of target user ID -> cross-signing self-signing key + SelfSigningKeys map[string]gomatrixserverlib.CrossSigningKey + // A map of target user ID -> cross-signing user-signing key + UserSigningKeys map[string]gomatrixserverlib.CrossSigningKey + // The request error, if any + Error *KeyError +} + type InputDeviceListUpdateRequest struct { Event gomatrixserverlib.DeviceListUpdateEvent } diff --git a/keyserver/internal/cross_signing.go b/keyserver/internal/cross_signing.go index 802d02b36..141a4eb2b 100644 --- a/keyserver/internal/cross_signing.go +++ b/keyserver/internal/cross_signing.go @@ -17,6 +17,7 @@ package internal import ( "context" "crypto/ed25519" + "database/sql" "encoding/json" "fmt" "strings" @@ -104,7 +105,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P // If the user hasn't given a new master key, then let's go and get their // existing keys from the database. if !hasMasterKey { - existingKeys, err := a.DB.CrossSigningKeysForUser(ctx, req.UserID) + existingKeys, err := a.DB.CrossSigningKeysDataForUser(ctx, req.UserID) if err != nil { res.Error = &api.KeyError{ Err: "Retrieving cross-signing keys from database failed: " + err.Error(), @@ -177,21 +178,24 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P } for purpose, key := range toVerify { // Collect together the key IDs we need to verify with. This will include - // all of the key IDs specified in the signatures. We don't do this for - // the master key because we have no means to verify the signatures - we - // instead just need to store them. - if purpose != gomatrixserverlib.CrossSigningKeyPurposeMaster { - // Marshal the specific key back into JSON so that we can verify the - // signature of it. - keyJSON, err := json.Marshal(key) - if err != nil { - res.Error = &api.KeyError{ - Err: fmt.Sprintf("The JSON of the key section is invalid: %s", err.Error()), - } - return + // all of the key IDs specified in the signatures. + keyJSON, err := json.Marshal(key) + if err != nil { + res.Error = &api.KeyError{ + Err: fmt.Sprintf("The JSON of the key section is invalid: %s", err.Error()), } + return + } - // Now check if the subkey is signed by the master key. + switch purpose { + case gomatrixserverlib.CrossSigningKeyPurposeMaster: + // The master key might have a signature attached to it from the + // previous key, or from a device key, but there's no real need + // to verify it. Clients will perform key checks when the master + // key changes. + + default: + // Sub-keys should be signed by the master key. if err := gomatrixserverlib.VerifyJSON(req.UserID, masterKeyID, ed25519.PublicKey(masterKey), keyJSON); err != nil { res.Error = &api.KeyError{ Err: fmt.Sprintf("The %q sub-key failed master key signature verification: %s", purpose, err.Error()), @@ -212,10 +216,44 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P res.Error = &api.KeyError{ Err: fmt.Sprintf("a.DB.StoreCrossSigningKeysForUser: %s", err), } + return + } + + // Now upload any signatures that were included with the keys. + for _, key := range toVerify { + var targetKeyID gomatrixserverlib.KeyID + for targetKey := range key.Keys { // iterates once, see sanityCheckKey + targetKeyID = targetKey + } + for sigUserID, forSigUserID := range key.Signatures { + if sigUserID != req.UserID { + continue + } + for sigKeyID, sigBytes := range forSigUserID { + if err := a.DB.StoreCrossSigningSigsForTarget(ctx, sigUserID, sigKeyID, req.UserID, targetKeyID, sigBytes); err != nil { + res.Error = &api.KeyError{ + Err: fmt.Sprintf("a.DB.StoreCrossSigningSigsForTarget: %s", err), + } + return + } + } + } } } func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req *api.PerformUploadDeviceSignaturesRequest, res *api.PerformUploadDeviceSignaturesResponse) { + // Before we do anything, we need the master and self-signing keys for this user. + // Then we can verify the signatures make sense. + queryReq := &api.QueryKeysRequest{ + UserID: req.UserID, + UserToDevices: map[string][]string{}, + } + queryRes := &api.QueryKeysResponse{} + for userID := range req.Signatures { + queryReq.UserToDevices[userID] = []string{} + } + a.QueryKeys(ctx, queryReq, queryRes) + selfSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{} otherSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{} @@ -254,14 +292,14 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req } } - if err := a.processSelfSignatures(ctx, req.UserID, selfSignatures); err != nil { + if err := a.processSelfSignatures(ctx, req.UserID, queryRes, selfSignatures); err != nil { res.Error = &api.KeyError{ Err: fmt.Sprintf("a.processSelfSignatures: %s", err), } return } - if err := a.processOtherSignatures(ctx, req.UserID, otherSignatures); err != nil { + if err := a.processOtherSignatures(ctx, req.UserID, queryRes, otherSignatures); err != nil { res.Error = &api.KeyError{ Err: fmt.Sprintf("a.processOtherSignatures: %s", err), } @@ -270,7 +308,7 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req } func (a *KeyInternalAPI) processSelfSignatures( - ctx context.Context, _ string, + ctx context.Context, _ string, queryRes *api.QueryKeysResponse, signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice, ) error { // Here we will process: @@ -281,8 +319,39 @@ func (a *KeyInternalAPI) processSelfSignatures( for targetKeyID, signature := range forTargetUserID { switch sig := signature.CrossSigningBody.(type) { case *gomatrixserverlib.CrossSigningKey: + // The user is signing their master key with one of their devices + // The QueryKeys response should contain the device key hopefully. + // First we need to marshal the blob back into JSON so we can verify + // it. + j, err := json.Marshal(sig) + if err != nil { + return fmt.Errorf("json.Marshal: %w", err) + } + for originUserID, forOriginUserID := range sig.Signatures { + originDeviceKeys, ok := queryRes.DeviceKeys[originUserID] + if !ok { + return fmt.Errorf("missing device keys for user %q", originUserID) + } + for originKeyID, originSig := range forOriginUserID { + originDeviceKeyID := gomatrixserverlib.KeyID("ed25519:" + originKeyID) + + var originKey gomatrixserverlib.DeviceKeys + if err := json.Unmarshal(originDeviceKeys[string(originKeyID)], &originKey); err != nil { + return fmt.Errorf("json.Unmarshal: %w", err) + } + + originSigningKey, ok := originKey.Keys[originDeviceKeyID] + if !ok { + return fmt.Errorf("missing origin signing key %q", originDeviceKeyID) + } + originSigningKeyPublic := ed25519.PublicKey(originSigningKey) + + if err := gomatrixserverlib.VerifyJSON(originUserID, originDeviceKeyID, originSigningKeyPublic, j); err != nil { + return fmt.Errorf("gomatrixserverlib.VerifyJSON: %w", err) + } + if err := a.DB.StoreCrossSigningSigsForTarget( ctx, originUserID, originKeyID, targetUserID, targetKeyID, originSig, ); err != nil { @@ -292,8 +361,35 @@ func (a *KeyInternalAPI) processSelfSignatures( } case *gomatrixserverlib.DeviceKeys: + // The user is signing one of their devices with their self-signing key + // The QueryKeys response should contain the master key hopefully. + // First we need to marshal the blob back into JSON so we can verify + // it. + j, err := json.Marshal(sig) + if err != nil { + return fmt.Errorf("json.Marshal: %w", err) + } + for originUserID, forOriginUserID := range sig.Signatures { for originKeyID, originSig := range forOriginUserID { + originSelfSigningKeys, ok := queryRes.SelfSigningKeys[originUserID] + if !ok { + return fmt.Errorf("missing self-signing key for user %q", originUserID) + } + + var originSelfSigningKeyID gomatrixserverlib.KeyID + var originSelfSigningKey gomatrixserverlib.Base64Bytes + for keyID, key := range originSelfSigningKeys.Keys { + originSelfSigningKeyID, originSelfSigningKey = keyID, key + break + } + + originSelfSigningKeyPublic := ed25519.PublicKey(originSelfSigningKey) + + if err := gomatrixserverlib.VerifyJSON(originUserID, originSelfSigningKeyID, originSelfSigningKeyPublic, j); err != nil { + return fmt.Errorf("gomatrixserverlib.VerifyJSON: %w", err) + } + if err := a.DB.StoreCrossSigningSigsForTarget( ctx, originUserID, originKeyID, targetUserID, targetKeyID, originSig, ); err != nil { @@ -312,7 +408,7 @@ func (a *KeyInternalAPI) processSelfSignatures( } func (a *KeyInternalAPI) processOtherSignatures( - ctx context.Context, userID string, + ctx context.Context, userID string, queryRes *api.QueryKeysResponse, signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice, ) error { // Here we will process: @@ -331,20 +427,14 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase( continue } - for keyType, keyData := range keys { - b64 := keyData.Encode() - keyID := gomatrixserverlib.KeyID("ed25519:" + b64) - key := gomatrixserverlib.CrossSigningKey{ - UserID: userID, - Usage: []gomatrixserverlib.CrossSigningKeyPurpose{ - keyType, - }, - Keys: map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{ - keyID: keyData, - }, + for keyType, key := range keys { + var keyID gomatrixserverlib.KeyID + for id := range key.Keys { + keyID = id + break } - sigs, err := a.DB.CrossSigningSigsForTarget(ctx, userID, keyID) + sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, userID, keyID) if err != nil { logrus.WithError(err).Errorf("Failed to get cross-signing signatures for user %q key %q", userID, keyID) continue @@ -360,7 +450,7 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase( key.Signatures[originUserID][originKeyID] = signature } - for originUserID, forOrigin := range sigs { + for originUserID, forOrigin := range sigMap { for originKeyID, signature := range forOrigin { switch { case req.UserID != "" && originUserID == req.UserID: @@ -387,3 +477,70 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase( } } } + +func (a *KeyInternalAPI) QuerySignatures(ctx context.Context, req *api.QuerySignaturesRequest, res *api.QuerySignaturesResponse) { + for targetUserID, forTargetUser := range req.TargetIDs { + for _, targetKeyID := range forTargetUser { + keyMap, err := a.DB.CrossSigningKeysForUser(ctx, targetUserID) + if err != nil { + if err == sql.ErrNoRows { + continue + } + res.Error = &api.KeyError{ + Err: fmt.Sprintf("a.DB.CrossSigningKeysForUser: %s", err), + } + } + + for targetPurpose, targetKey := range keyMap { + switch targetPurpose { + case gomatrixserverlib.CrossSigningKeyPurposeMaster: + if res.MasterKeys == nil { + res.MasterKeys = map[string]gomatrixserverlib.CrossSigningKey{} + } + res.MasterKeys[targetUserID] = targetKey + + case gomatrixserverlib.CrossSigningKeyPurposeSelfSigning: + if res.SelfSigningKeys == nil { + res.SelfSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{} + } + res.SelfSigningKeys[targetUserID] = targetKey + + case gomatrixserverlib.CrossSigningKeyPurposeUserSigning: + if res.UserSigningKeys == nil { + res.UserSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{} + } + res.UserSigningKeys[targetUserID] = targetKey + } + } + + sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, targetUserID, targetKeyID) + if err != nil { + if err == sql.ErrNoRows { + continue + } + res.Error = &api.KeyError{ + Err: fmt.Sprintf("a.DB.CrossSigningSigsForTarget: %s", err), + } + return + } + + for sourceUserID, forSourceUser := range sigMap { + for sourceKeyID, sourceSig := range forSourceUser { + if res.Signatures == nil { + res.Signatures = map[string]map[gomatrixserverlib.KeyID]types.CrossSigningSigMap{} + } + if _, ok := res.Signatures[targetUserID]; !ok { + res.Signatures[targetUserID] = map[gomatrixserverlib.KeyID]types.CrossSigningSigMap{} + } + if _, ok := res.Signatures[targetUserID][targetKeyID]; !ok { + res.Signatures[targetUserID][targetKeyID] = types.CrossSigningSigMap{} + } + if _, ok := res.Signatures[targetUserID][targetKeyID][sourceUserID]; !ok { + res.Signatures[targetUserID][targetKeyID][sourceUserID] = map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{} + } + res.Signatures[targetUserID][targetKeyID][sourceUserID][sourceKeyID] = sourceSig + } + } + } + } +} diff --git a/keyserver/internal/internal.go b/keyserver/internal/internal.go index c5711e73c..28638c294 100644 --- a/keyserver/internal/internal.go +++ b/keyserver/internal/internal.go @@ -300,12 +300,38 @@ func (a *KeyInternalAPI) QueryKeys(ctx context.Context, req *api.QueryKeysReques // attempt to satisfy key queries from the local database first as we should get device updates pushed to us domainToDeviceKeys = a.remoteKeysFromDatabase(ctx, res, domainToDeviceKeys) - if len(domainToDeviceKeys) == 0 && len(domainToCrossSigningKeys) == 0 { - return // nothing to query + if len(domainToDeviceKeys) > 0 || len(domainToCrossSigningKeys) > 0 { + // perform key queries for remote devices + a.queryRemoteKeys(ctx, req.Timeout, res, domainToDeviceKeys, domainToCrossSigningKeys) } - // perform key queries for remote devices - a.queryRemoteKeys(ctx, req.Timeout, res, domainToDeviceKeys, domainToCrossSigningKeys) + // Finally, append signatures that we know about + // TODO: This is horrible because we need to round-trip the signature from + // JSON, add the signatures and marshal it again, for some reason? + for userID, forUserID := range res.DeviceKeys { + for keyID, key := range forUserID { + sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, userID, gomatrixserverlib.KeyID(keyID)) + if err != nil { + logrus.WithError(err).Errorf("a.DB.CrossSigningSigsForTarget failed") + continue + } + if len(sigMap) == 0 { + continue + } + var deviceKey gomatrixserverlib.DeviceKeys + if err = json.Unmarshal(key, &deviceKey); err != nil { + continue + } + for sourceUserID, forSourceUser := range sigMap { + for sourceKeyID, sourceSig := range forSourceUser { + deviceKey.Signatures[sourceUserID][sourceKeyID] = sourceSig + } + } + if js, err := json.Marshal(deviceKey); err == nil { + res.DeviceKeys[userID][keyID] = js + } + } + } } func (a *KeyInternalAPI) remoteKeysFromDatabase( diff --git a/keyserver/inthttp/client.go b/keyserver/inthttp/client.go index b685ae1a5..15870571e 100644 --- a/keyserver/inthttp/client.go +++ b/keyserver/inthttp/client.go @@ -36,6 +36,7 @@ const ( QueryKeyChangesPath = "/keyserver/queryKeyChanges" QueryOneTimeKeysPath = "/keyserver/queryOneTimeKeys" QueryDeviceMessagesPath = "/keyserver/queryDeviceMessages" + QuerySignaturesPath = "/keyserver/querySignatures" ) // NewKeyServerClient creates a KeyInternalAPI implemented by talking to a HTTP POST API. @@ -211,3 +212,20 @@ func (h *httpKeyInternalAPI) PerformUploadDeviceSignatures( } } } + +func (h *httpKeyInternalAPI) QuerySignatures( + ctx context.Context, + request *api.QuerySignaturesRequest, + response *api.QuerySignaturesResponse, +) { + span, ctx := opentracing.StartSpanFromContext(ctx, "QuerySignatures") + defer span.Finish() + + apiURL := h.apiURL + QuerySignaturesPath + err := httputil.PostJSON(ctx, span, h.httpClient, apiURL, request, response) + if err != nil { + response.Error = &api.KeyError{ + Err: err.Error(), + } + } +} diff --git a/keyserver/inthttp/server.go b/keyserver/inthttp/server.go index ab096c156..ac70e3e55 100644 --- a/keyserver/inthttp/server.go +++ b/keyserver/inthttp/server.go @@ -124,4 +124,15 @@ func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) { return util.JSONResponse{Code: http.StatusOK, JSON: &response} }), ) + internalAPIMux.Handle(QuerySignaturesPath, + httputil.MakeInternalAPI("querySignatures", func(req *http.Request) util.JSONResponse { + request := api.QuerySignaturesRequest{} + response := api.QuerySignaturesResponse{} + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { + return util.MessageResponse(http.StatusBadRequest, err.Error()) + } + s.QuerySignatures(req.Context(), &request, &response) + return util.JSONResponse{Code: http.StatusOK, JSON: &response} + }), + ) } diff --git a/keyserver/storage/interface.go b/keyserver/storage/interface.go index 756dc32ad..b9db81ad6 100644 --- a/keyserver/storage/interface.go +++ b/keyserver/storage/interface.go @@ -78,7 +78,8 @@ type Database interface { // MarkDeviceListStale sets the stale bit for this user to isStale. MarkDeviceListStale(ctx context.Context, userID string, isStale bool) error - CrossSigningKeysForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error) + CrossSigningKeysForUser(ctx context.Context, userID string) (map[gomatrixserverlib.CrossSigningKeyPurpose]gomatrixserverlib.CrossSigningKey, error) + CrossSigningKeysDataForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error) CrossSigningSigsForTarget(ctx context.Context, targetUserID string, targetKeyID gomatrixserverlib.KeyID) (types.CrossSigningSigMap, error) StoreCrossSigningKeysForUser(ctx context.Context, userID string, keyMap types.CrossSigningKeyMap) error diff --git a/keyserver/storage/shared/storage.go b/keyserver/storage/shared/storage.go index 767242950..64ce53ef1 100644 --- a/keyserver/storage/shared/storage.go +++ b/keyserver/storage/shared/storage.go @@ -159,7 +159,46 @@ func (d *Database) MarkDeviceListStale(ctx context.Context, userID string, isSta } // CrossSigningKeysForUser returns the latest known cross-signing keys for a user, if any. -func (d *Database) CrossSigningKeysForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error) { +func (d *Database) CrossSigningKeysForUser(ctx context.Context, userID string) (map[gomatrixserverlib.CrossSigningKeyPurpose]gomatrixserverlib.CrossSigningKey, error) { + keyMap, err := d.CrossSigningKeysTable.SelectCrossSigningKeysForUser(ctx, nil, userID) + if err != nil { + return nil, fmt.Errorf("d.CrossSigningKeysTable.SelectCrossSigningKeysForUser: %w", err) + } + results := map[gomatrixserverlib.CrossSigningKeyPurpose]gomatrixserverlib.CrossSigningKey{} + for purpose, key := range keyMap { + keyID := gomatrixserverlib.KeyID("ed25519:" + key.Encode()) + result := gomatrixserverlib.CrossSigningKey{ + UserID: userID, + Usage: []gomatrixserverlib.CrossSigningKeyPurpose{purpose}, + Keys: map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{ + keyID: key, + }, + } + sigMap, err := d.CrossSigningSigsTable.SelectCrossSigningSigsForTarget(ctx, nil, userID, keyID) + if err != nil { + continue + } + for sigUserID, forSigUserID := range sigMap { + if userID != sigUserID { + continue + } + if result.Signatures == nil { + result.Signatures = map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{} + } + if _, ok := result.Signatures[sigUserID]; !ok { + result.Signatures[sigUserID] = map[gomatrixserverlib.KeyID]gomatrixserverlib.Base64Bytes{} + } + for sigKeyID, sigBytes := range forSigUserID { + result.Signatures[sigUserID][sigKeyID] = sigBytes + } + } + results[purpose] = result + } + return results, nil +} + +// CrossSigningKeysForUser returns the latest known cross-signing keys for a user, if any. +func (d *Database) CrossSigningKeysDataForUser(ctx context.Context, userID string) (types.CrossSigningKeyMap, error) { return d.CrossSigningKeysTable.SelectCrossSigningKeysForUser(ctx, nil, userID) } diff --git a/syncapi/internal/keychange_test.go b/syncapi/internal/keychange_test.go index 38be34f65..0c567a962 100644 --- a/syncapi/internal/keychange_test.go +++ b/syncapi/internal/keychange_test.go @@ -49,6 +49,8 @@ func (k *mockKeyAPI) QueryDeviceMessages(ctx context.Context, req *keyapi.QueryD } func (k *mockKeyAPI) InputDeviceListUpdate(ctx context.Context, req *keyapi.InputDeviceListUpdateRequest, res *keyapi.InputDeviceListUpdateResponse) { +} +func (k *mockKeyAPI) QuerySignatures(ctx context.Context, req *keyapi.QuerySignaturesRequest, res *keyapi.QuerySignaturesResponse) { } type mockRoomserverAPI struct { From b1377d991a1d4fd71cf275d96da343ca558993b7 Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Mon, 9 Aug 2021 14:35:24 +0100 Subject: [PATCH 3/3] Cross-signing signature handling (#1965) * Handle other signatures * Decorate key ID properly * Match by key IDs * Tweaks * Fixes * Fix /user/keys/query bug, review comments, update sytest-whitelist * Various wtweaks * Fix wiring for keyserver in API mode * Additional fixes --- cmd/dendrite-monolith-server/main.go | 5 + federationapi/routing/devices.go | 7 +- federationapi/routing/keys.go | 10 +- go.mod | 2 +- go.sum | 4 +- keyserver/api/api.go | 4 +- keyserver/internal/cross_signing.go | 186 +++++++++++++++------------ keyserver/internal/internal.go | 24 ++-- keyserver/inthttp/server.go | 4 +- sytest-whitelist | 1 + 10 files changed, 145 insertions(+), 102 deletions(-) diff --git a/cmd/dendrite-monolith-server/main.go b/cmd/dendrite-monolith-server/main.go index bb313e57a..4d8e2ee15 100644 --- a/cmd/dendrite-monolith-server/main.go +++ b/cmd/dendrite-monolith-server/main.go @@ -120,6 +120,11 @@ func main() { Impl: userAPI, } } + // needs to be after the SetUserAPI call above + if base.UseHTTPAPIs { + keyserver.AddInternalRoutes(base.InternalAPIMux, keyAPI) + keyAPI = base.KeyServerHTTPClient() + } eduInputAPI := eduserver.NewInternalAPI( base, cache.New(), userAPI, diff --git a/federationapi/routing/devices.go b/federationapi/routing/devices.go index b397c5460..4cd199960 100644 --- a/federationapi/routing/devices.go +++ b/federationapi/routing/devices.go @@ -38,12 +38,11 @@ func GetUserDevices( } sigReq := &keyapi.QuerySignaturesRequest{ - TargetIDs: map[string][]gomatrixserverlib.KeyID{}, + TargetIDs: map[string][]gomatrixserverlib.KeyID{ + userID: {}, + }, } sigRes := &keyapi.QuerySignaturesResponse{} - for _, dev := range res.Devices { - sigReq.TargetIDs[userID] = append(sigReq.TargetIDs[userID], gomatrixserverlib.KeyID(dev.DeviceID)) - } keyAPI.QuerySignatures(req.Context(), sigReq, sigRes) response := gomatrixserverlib.RespUserDevices{ diff --git a/federationapi/routing/keys.go b/federationapi/routing/keys.go index d73161e94..bba3272b9 100644 --- a/federationapi/routing/keys.go +++ b/federationapi/routing/keys.go @@ -71,8 +71,14 @@ func QueryDeviceKeys( return util.JSONResponse{ Code: 200, JSON: struct { - DeviceKeys interface{} `json:"device_keys"` - }{queryRes.DeviceKeys}, + DeviceKeys interface{} `json:"device_keys"` + MasterKeys interface{} `json:"master_keys"` + SelfSigningKeys interface{} `json:"self_signing_keys"` + }{ + queryRes.DeviceKeys, + queryRes.MasterKeys, + queryRes.SelfSigningKeys, + }, } } diff --git a/go.mod b/go.mod index 39f6020ce..e5d157565 100644 --- a/go.mod +++ b/go.mod @@ -31,7 +31,7 @@ require ( github.com/matrix-org/go-http-js-libp2p v0.0.0-20200518170932-783164aeeda4 github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 - github.com/matrix-org/gomatrixserverlib v0.0.0-20210805104751-03e40fa2c0e1 + github.com/matrix-org/gomatrixserverlib v0.0.0-20210809130922-d9c3f400582b github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0 github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b github.com/matrix-org/util v0.0.0-20200807132607-55161520e1d4 diff --git a/go.sum b/go.sum index df5e2b857..d848988da 100644 --- a/go.sum +++ b/go.sum @@ -994,8 +994,8 @@ github.com/matrix-org/go-sqlite3-js v0.0.0-20210709140738-b0d1ba599a6d/go.mod h1 github.com/matrix-org/gomatrix v0.0.0-20190528120928-7df988a63f26/go.mod h1:3fxX6gUjWyI/2Bt7J1OLhpCzOfO/bB3AiX0cJtEKud0= github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 h1:ZtO5uywdd5dLDCud4r0r55eP4j9FuUNpl60Gmntcop4= github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16/go.mod h1:/gBX06Kw0exX1HrwmoBibFA98yBk/jxKpGVeyQbff+s= -github.com/matrix-org/gomatrixserverlib v0.0.0-20210805104751-03e40fa2c0e1 h1:ExS9AmOWYSZ4DR7W7Eqm7glP/g/u/CTVLAu9blAnve4= -github.com/matrix-org/gomatrixserverlib v0.0.0-20210805104751-03e40fa2c0e1/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU= +github.com/matrix-org/gomatrixserverlib v0.0.0-20210809130922-d9c3f400582b h1:8St1B8QmlvMLsOmGqW3++0akUs0250IAi+AGcr5faxw= +github.com/matrix-org/gomatrixserverlib v0.0.0-20210809130922-d9c3f400582b/go.mod h1:JsAzE1Ll3+gDWS9JSUHPJiiyAksvOOnGWF2nXdg4ZzU= github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0 h1:HZCzy4oVzz55e+cOMiX/JtSF2UOY1evBl2raaE7ACcU= github.com/matrix-org/naffka v0.0.0-20210623111924-14ff508b58e0/go.mod h1:sjyPyRxKM5uw1nD2cJ6O2OxI6GOqyVBfNXqKjBZTBZE= github.com/matrix-org/pinecone v0.0.0-20210623102758-74f885644c1b h1:5X5vdWQ13xrNkJVqaJHPsrt7rKkMJH5iac0EtfOuxSg= diff --git a/keyserver/api/api.go b/keyserver/api/api.go index 520562e7a..aa6df96f8 100644 --- a/keyserver/api/api.go +++ b/keyserver/api/api.go @@ -160,7 +160,7 @@ type PerformClaimKeysResponse struct { type PerformUploadDeviceKeysRequest struct { gomatrixserverlib.CrossSigningKeys // The user that uploaded the key, should be populated by the clientapi. - UserID string `json:"user_id"` + UserID string } type PerformUploadDeviceKeysResponse struct { @@ -170,7 +170,7 @@ type PerformUploadDeviceKeysResponse struct { type PerformUploadDeviceSignaturesRequest struct { Signatures map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice // The user that uploaded the sig, should be populated by the clientapi. - UserID string `json:"user_id"` + UserID string } type PerformUploadDeviceSignaturesResponse struct { diff --git a/keyserver/internal/cross_signing.go b/keyserver/internal/cross_signing.go index 141a4eb2b..4009dd459 100644 --- a/keyserver/internal/cross_signing.go +++ b/keyserver/internal/cross_signing.go @@ -15,6 +15,7 @@ package internal import ( + "bytes" "context" "crypto/ed25519" "database/sql" @@ -78,8 +79,8 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P } return } - hasMasterKey = true for _, keyData := range req.MasterKey.Keys { // iterates once, because sanityCheckKey requires one key + hasMasterKey = true masterKey = keyData } } @@ -116,46 +117,11 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P masterKey, hasMasterKey = existingKeys[gomatrixserverlib.CrossSigningKeyPurposeMaster] } - // If the user isn't a local user and we haven't successfully found a key - // through any local means then ask over federation. - if !hasMasterKey { - _, host, err := gomatrixserverlib.SplitID('@', req.UserID) - if err != nil { - res.Error = &api.KeyError{ - Err: "Retrieving cross-signing keys from federation failed: " + err.Error(), - } - return - } - keys, err := a.FedClient.QueryKeys(ctx, host, map[string][]string{ - req.UserID: {}, - }) - if err != nil { - res.Error = &api.KeyError{ - Err: "Retrieving cross-signing keys from federation failed: " + err.Error(), - } - return - } - switch k := keys.MasterKeys[req.UserID].CrossSigningBody.(type) { - case *gomatrixserverlib.CrossSigningKey: - if err := sanityCheckKey(*k, req.UserID, gomatrixserverlib.CrossSigningKeyPurposeMaster); err != nil { - res.Error = &api.KeyError{ - Err: "Master key sanity check failed: " + err.Error(), - } - return - } - default: - res.Error = &api.KeyError{ - Err: "Unexpected type for master key retrieved from federation", - } - return - } - } - // If we still don't have a master key at this point then there's nothing else // we can do - we've checked both the request and the database. if !hasMasterKey { res.Error = &api.KeyError{ - Err: "No master key was found, either in the database or in the request!", + Err: "No master key was found either in the database or in the request!", IsMissingParam: true, } return @@ -176,6 +142,15 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P if len(req.UserSigningKey.Keys) > 0 { toVerify[gomatrixserverlib.CrossSigningKeyPurposeUserSigning] = req.UserSigningKey } + + if len(toVerify) == 0 { + res.Error = &api.KeyError{ + Err: "No supplied keys available for verification", + IsMissingParam: true, + } + return + } + for purpose, key := range toVerify { // Collect together the key IDs we need to verify with. This will include // all of the key IDs specified in the signatures. @@ -212,6 +187,14 @@ func (a *KeyInternalAPI) PerformUploadDeviceKeys(ctx context.Context, req *api.P } } + if len(toStore) == 0 { + res.Error = &api.KeyError{ + Err: "No supplied keys passed verification", + IsMissingParam: true, + } + return + } + if err := a.DB.StoreCrossSigningKeysForUser(ctx, req.UserID, toStore); err != nil { res.Error = &api.KeyError{ Err: fmt.Sprintf("a.DB.StoreCrossSigningKeysForUser: %s", err), @@ -257,6 +240,8 @@ func (a *KeyInternalAPI) PerformUploadDeviceSignatures(ctx context.Context, req selfSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{} otherSignatures := map[string]map[gomatrixserverlib.KeyID]gomatrixserverlib.CrossSigningForKeyOrDevice{} + // Sort signatures into two groups: one where people have signed their own + // keys and one where people have signed someone elses for userID, forUserID := range req.Signatures { for keyID, keyOrDevice := range forUserID { switch key := keyOrDevice.CrossSigningBody.(type) { @@ -335,20 +320,18 @@ func (a *KeyInternalAPI) processSelfSignatures( } for originKeyID, originSig := range forOriginUserID { - originDeviceKeyID := gomatrixserverlib.KeyID("ed25519:" + originKeyID) - var originKey gomatrixserverlib.DeviceKeys if err := json.Unmarshal(originDeviceKeys[string(originKeyID)], &originKey); err != nil { return fmt.Errorf("json.Unmarshal: %w", err) } - originSigningKey, ok := originKey.Keys[originDeviceKeyID] + originSigningKey, ok := originKey.Keys[originKeyID] if !ok { - return fmt.Errorf("missing origin signing key %q", originDeviceKeyID) + return fmt.Errorf("missing origin signing key %q", originKeyID) } originSigningKeyPublic := ed25519.PublicKey(originSigningKey) - if err := gomatrixserverlib.VerifyJSON(originUserID, originDeviceKeyID, originSigningKeyPublic, j); err != nil { + if err := gomatrixserverlib.VerifyJSON(originUserID, originKeyID, originSigningKeyPublic, j); err != nil { return fmt.Errorf("gomatrixserverlib.VerifyJSON: %w", err) } @@ -414,6 +397,56 @@ func (a *KeyInternalAPI) processOtherSignatures( // Here we will process: // * A user signing someone else's master keys using their user-signing keys + for targetUserID, forTargetUserID := range signatures { + for _, signature := range forTargetUserID { + switch sig := signature.CrossSigningBody.(type) { + case *gomatrixserverlib.CrossSigningKey: + // Find the local copy of the master key. We'll use this to be + // sure that the supplied stanza matches the key that we think it + // should be. + masterKey, ok := queryRes.MasterKeys[targetUserID] + if !ok { + return fmt.Errorf("failed to find master key for user %q", targetUserID) + } + + // For each key ID, write the signatures. Maybe there'll be more + // than one algorithm in the future so it's best not to focus on + // everything being ed25519:. + for targetKeyID, suppliedKeyData := range sig.Keys { + // The master key will be supplied in the request, but we should + // make sure that it matches what we think the master key should + // actually be. + localKeyData, lok := masterKey.Keys[targetKeyID] + if !lok { + return fmt.Errorf("uploaded master key %q for user %q doesn't match local copy", targetKeyID, targetUserID) + } else if !bytes.Equal(suppliedKeyData, localKeyData) { + return fmt.Errorf("uploaded master key %q for user %q doesn't match local copy", targetKeyID, targetUserID) + } + + // We only care about the signatures from the uploading user, so + // we will ignore anything that didn't originate from them. + userSigs, ok := sig.Signatures[userID] + if !ok { + return fmt.Errorf("there are no signatures on master key %q from uploading user %q", targetKeyID, userID) + } + + for originKeyID, originSig := range userSigs { + if err := a.DB.StoreCrossSigningSigsForTarget( + ctx, userID, originKeyID, targetUserID, targetKeyID, originSig, + ); err != nil { + return fmt.Errorf("a.DB.StoreCrossSigningKeysForTarget: %w", err) + } + } + } + + default: + // Users should only be signing another person's master key, + // so if we're here, it's probably because it's actually a + // gomatrixserverlib.DeviceKeys, which doesn't make sense. + } + } + } + return nil } @@ -435,7 +468,7 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase( } sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, userID, keyID) - if err != nil { + if err != nil && err != sql.ErrNoRows { logrus.WithError(err).Errorf("Failed to get cross-signing signatures for user %q key %q", userID, keyID) continue } @@ -480,44 +513,39 @@ func (a *KeyInternalAPI) crossSigningKeysFromDatabase( func (a *KeyInternalAPI) QuerySignatures(ctx context.Context, req *api.QuerySignaturesRequest, res *api.QuerySignaturesResponse) { for targetUserID, forTargetUser := range req.TargetIDs { + keyMap, err := a.DB.CrossSigningKeysForUser(ctx, targetUserID) + if err != nil && err != sql.ErrNoRows { + res.Error = &api.KeyError{ + Err: fmt.Sprintf("a.DB.CrossSigningKeysForUser: %s", err), + } + continue + } + + for targetPurpose, targetKey := range keyMap { + switch targetPurpose { + case gomatrixserverlib.CrossSigningKeyPurposeMaster: + if res.MasterKeys == nil { + res.MasterKeys = map[string]gomatrixserverlib.CrossSigningKey{} + } + res.MasterKeys[targetUserID] = targetKey + + case gomatrixserverlib.CrossSigningKeyPurposeSelfSigning: + if res.SelfSigningKeys == nil { + res.SelfSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{} + } + res.SelfSigningKeys[targetUserID] = targetKey + + case gomatrixserverlib.CrossSigningKeyPurposeUserSigning: + if res.UserSigningKeys == nil { + res.UserSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{} + } + res.UserSigningKeys[targetUserID] = targetKey + } + } + for _, targetKeyID := range forTargetUser { - keyMap, err := a.DB.CrossSigningKeysForUser(ctx, targetUserID) - if err != nil { - if err == sql.ErrNoRows { - continue - } - res.Error = &api.KeyError{ - Err: fmt.Sprintf("a.DB.CrossSigningKeysForUser: %s", err), - } - } - - for targetPurpose, targetKey := range keyMap { - switch targetPurpose { - case gomatrixserverlib.CrossSigningKeyPurposeMaster: - if res.MasterKeys == nil { - res.MasterKeys = map[string]gomatrixserverlib.CrossSigningKey{} - } - res.MasterKeys[targetUserID] = targetKey - - case gomatrixserverlib.CrossSigningKeyPurposeSelfSigning: - if res.SelfSigningKeys == nil { - res.SelfSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{} - } - res.SelfSigningKeys[targetUserID] = targetKey - - case gomatrixserverlib.CrossSigningKeyPurposeUserSigning: - if res.UserSigningKeys == nil { - res.UserSigningKeys = map[string]gomatrixserverlib.CrossSigningKey{} - } - res.UserSigningKeys[targetUserID] = targetKey - } - } - sigMap, err := a.DB.CrossSigningSigsForTarget(ctx, targetUserID, targetKeyID) - if err != nil { - if err == sql.ErrNoRows { - continue - } + if err != nil && err != sql.ErrNoRows { res.Error = &api.KeyError{ Err: fmt.Sprintf("a.DB.CrossSigningSigsForTarget: %s", err), } diff --git a/keyserver/internal/internal.go b/keyserver/internal/internal.go index 28638c294..de2699114 100644 --- a/keyserver/internal/internal.go +++ b/keyserver/internal/internal.go @@ -372,9 +372,15 @@ func (a *KeyInternalAPI) queryRemoteKeys( domains := map[string]struct{}{} for domain := range domainToDeviceKeys { + if domain == string(a.ThisServer) { + continue + } domains[domain] = struct{}{} } for domain := range domainToCrossSigningKeys { + if domain == string(a.ThisServer) { + continue + } domains[domain] = struct{}{} } wg.Add(len(domains)) @@ -406,17 +412,11 @@ func (a *KeyInternalAPI) queryRemoteKeys( } for userID, body := range result.MasterKeys { - switch b := body.CrossSigningBody.(type) { - case *gomatrixserverlib.CrossSigningKey: - res.MasterKeys[userID] = *b - } + res.MasterKeys[userID] = body } for userID, body := range result.SelfSigningKeys { - switch b := body.CrossSigningBody.(type) { - case *gomatrixserverlib.CrossSigningKey: - res.SelfSigningKeys[userID] = *b - } + res.SelfSigningKeys[userID] = body } // TODO: do we want to persist these somewhere now @@ -430,8 +430,12 @@ func (a *KeyInternalAPI) queryRemoteKeysOnServer( res *api.QueryKeysResponse, ) { defer wg.Done() - fedCtx, cancel := context.WithTimeout(ctx, timeout) - defer cancel() + fedCtx := ctx + if timeout > 0 { + var cancel context.CancelFunc + fedCtx, cancel = context.WithTimeout(ctx, timeout) + defer cancel() + } // for users who we do not have any knowledge about, try to start doing device list updates for them // by hitting /users/devices - otherwise fallback to /keys/query which has nicer bulk properties but // lack a stream ID. diff --git a/keyserver/inthttp/server.go b/keyserver/inthttp/server.go index ac70e3e55..475544a5b 100644 --- a/keyserver/inthttp/server.go +++ b/keyserver/inthttp/server.go @@ -62,7 +62,7 @@ func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) { httputil.MakeInternalAPI("performUploadDeviceKeys", func(req *http.Request) util.JSONResponse { request := api.PerformUploadDeviceKeysRequest{} response := api.PerformUploadDeviceKeysResponse{} - if err := json.NewDecoder(req.Body).Decode(&request.CrossSigningKeys); err != nil { + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { return util.MessageResponse(http.StatusBadRequest, err.Error()) } s.PerformUploadDeviceKeys(req.Context(), &request, &response) @@ -73,7 +73,7 @@ func AddRoutes(internalAPIMux *mux.Router, s api.KeyInternalAPI) { httputil.MakeInternalAPI("performUploadDeviceSignatures", func(req *http.Request) util.JSONResponse { request := api.PerformUploadDeviceSignaturesRequest{} response := api.PerformUploadDeviceSignaturesResponse{} - if err := json.NewDecoder(req.Body).Decode(&request.Signatures); err != nil { + if err := json.NewDecoder(req.Body).Decode(&request); err != nil { return util.MessageResponse(http.StatusBadRequest, err.Error()) } s.PerformUploadDeviceSignatures(req.Context(), &request, &response) diff --git a/sytest-whitelist b/sytest-whitelist index 27109e602..d2f2a1c7d 100644 --- a/sytest-whitelist +++ b/sytest-whitelist @@ -553,3 +553,4 @@ Deleted & recreated backups are empty Can upload self-signing keys Fails to upload self-signing keys with no auth Fails to upload self-signing key without master key +can fetch self-signing keys over federation