diff --git a/client.go b/client.go index 8120c7dd..7fcfec03 100644 --- a/client.go +++ b/client.go @@ -1105,6 +1105,12 @@ func (cli *Client) UploadCrossSigningKeys(keys *UploadCrossSigningKeysReq, uiAut return err } +func (cli *Client) UploadSignatures(req *ReqUploadSignatures) (resp *RespUploadSignatures, err error) { + urlPath := cli.BuildBaseURL("_matrix", "client", "unstable", "keys", "signatures", "upload") + _, err = cli.MakeRequest("POST", urlPath, req, &resp) + return +} + // GetPushRules returns the push notification rules for the global scope. func (cli *Client) GetPushRules() (*pushrules.PushRuleset, error) { return cli.GetScopedPushRules("global") diff --git a/crypto/cross_sign.go b/crypto/cross_sign.go index 3d175d39..bcb60125 100644 --- a/crypto/cross_sign.go +++ b/crypto/cross_sign.go @@ -7,6 +7,7 @@ package crypto import ( + "github.com/pkg/errors" "maunium.net/go/mautrix" "maunium.net/go/mautrix/crypto/olm" "maunium.net/go/mautrix/id" @@ -200,3 +201,65 @@ func (mach *OlmMachine) uploadCrossSigningKeysToServer(keys *CrossSigningKeysCac } }) } + +// SignUserAndUpload creates a cross-signing signature for a user, stores it and uploads it to the server. +func (mach *OlmMachine) SignUserAndUpload(userID id.UserID) error { + if mach.crossSigningKeys == nil { + return errors.New("No cross-signing keys found") + } + if userID == mach.Client.UserID { + return nil + } + + keys, err := mach.CryptoStore.GetCrossSigningKeys(userID) + if err != nil { + return err + } + masterKey, ok := keys[id.XSUsageMaster] + if !ok { + return errors.Errorf("No master key found for user %v", userID) + } + + userSigningKey := mach.crossSigningKeys.UserSigningKey + masterKeyObj := mautrix.ReqKeysSignatures{ + UserID: userID, + Usage: []id.CrossSigningUsage{id.XSUsageMaster}, + Keys: map[id.KeyID]id.Ed25519{ + id.NewKeyID(id.KeyAlgorithmEd25519, masterKey.String()): masterKey, + }, + } + signature, err := userSigningKey.SignJSON(masterKeyObj) + if err != nil { + return err + } + masterKeyObj.Signatures = mautrix.Signatures{ + mach.Client.UserID: map[id.KeyID]string{ + id.NewKeyID(id.KeyAlgorithmEd25519, userSigningKey.PublicKey.String()): signature, + }, + } + mach.Log.Trace("Signed master key for user %v: `%v`", userID, signature) + + resp, err := mach.Client.UploadSignatures(&mautrix.ReqUploadSignatures{ + userID: map[string]mautrix.ReqKeysSignatures{ + masterKey.String(): masterKeyObj, + }, + }) + + if err != nil { + return err + } + if len(resp.Failures) > 0 { + return errors.Errorf("Key uploading failures: %v", resp.Failures) + } + + if err := mach.CryptoStore.PutSignature(userID, masterKey, mach.Client.UserID, userSigningKey.PublicKey, signature); err != nil { + return err + } + + return nil +} + +// SignDeviceAndUpload creates a cross-signing signature for a device, stores it and uploads it to the server. +func (mach *OlmMachine) SignDeviceAndUpload(device *DeviceIdentity) error { + return nil +} diff --git a/crypto/sql_store_upgrade/upgrade.go b/crypto/sql_store_upgrade/upgrade.go index 6fb6ada5..a4bd2cdd 100644 --- a/crypto/sql_store_upgrade/upgrade.go +++ b/crypto/sql_store_upgrade/upgrade.go @@ -211,7 +211,7 @@ var Upgrades = [...]upgradeFunc{ if _, err := tx.Exec( `CREATE TABLE IF NOT EXISTS crypto_cross_signing_keys ( user_id VARCHAR(255) NOT NULL, - usage CHAR(20) NOT NULL, + usage VARCHAR(20) NOT NULL, key CHAR(43) NOT NULL, PRIMARY KEY (user_id, usage) )`, diff --git a/requests.go b/requests.go index 4cc5bd8a..520b301a 100644 --- a/requests.go +++ b/requests.go @@ -181,12 +181,12 @@ type ReqUploadKeys struct { } type ReqKeysSignatures struct { - UserID id.UserID `json:"user_id"` - DeviceID id.DeviceID `json:"device_id,omitempty"` - Algorithms []id.Algorithm `json:"algorithms,omitempty"` - Usage []id.CrossSigningUsage `json:"usage,omitempty"` - Keys KeyMap `json:"keys"` - Signatures Signatures `json:"signatures"` + UserID id.UserID `json:"user_id"` + DeviceID id.DeviceID `json:"device_id,omitempty"` + Algorithms []id.Algorithm `json:"algorithms,omitempty"` + Usage []id.CrossSigningUsage `json:"usage,omitempty"` + Keys map[id.KeyID]id.Ed25519 `json:"keys"` + Signatures Signatures `json:"signatures"` } type ReqUploadSignatures map[id.UserID]map[string]ReqKeysSignatures