add vendoring
This commit is contained in:
332
vendor/maunium.net/go/mautrix/crypto/verification_in_room.go
generated
vendored
Normal file
332
vendor/maunium.net/go/mautrix/crypto/verification_in_room.go
generated
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
// Copyright (c) 2020 Nikos Filippakis
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package crypto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix/crypto/canonicaljson"
|
||||
"maunium.net/go/mautrix/crypto/olm"
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/id"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNoVerificationFromDevice = errors.New("from_device field is empty")
|
||||
ErrNoVerificationMethods = errors.New("verification method list is empty")
|
||||
ErrNoRelatesTo = errors.New("missing m.relates_to info")
|
||||
)
|
||||
|
||||
// ProcessInRoomVerification is a callback that is to be called when a client receives a message
|
||||
// related to in-room verification.
|
||||
//
|
||||
// Currently this is not automatically called, so you must add the listener yourself.
|
||||
// Note that in-room verification events are wrapped in m.room.encrypted, but this expects the decrypted events.
|
||||
func (mach *OlmMachine) ProcessInRoomVerification(evt *event.Event) error {
|
||||
if evt.Sender == mach.Client.UserID {
|
||||
// nothing to do if the message is our own
|
||||
return nil
|
||||
}
|
||||
if relatable, ok := evt.Content.Parsed.(event.Relatable); !ok || relatable.OptionalGetRelatesTo() == nil {
|
||||
return ErrNoRelatesTo
|
||||
}
|
||||
|
||||
switch content := evt.Content.Parsed.(type) {
|
||||
case *event.MessageEventContent:
|
||||
if content.MsgType == event.MsgVerificationRequest {
|
||||
if content.FromDevice == "" {
|
||||
return ErrNoVerificationFromDevice
|
||||
}
|
||||
if content.Methods == nil {
|
||||
return ErrNoVerificationMethods
|
||||
}
|
||||
|
||||
newContent := &event.VerificationRequestEventContent{
|
||||
FromDevice: content.FromDevice,
|
||||
Methods: content.Methods,
|
||||
Timestamp: evt.Timestamp,
|
||||
TransactionID: evt.ID.String(),
|
||||
}
|
||||
mach.handleVerificationRequest(evt.Sender, newContent, evt.ID.String(), evt.RoomID)
|
||||
}
|
||||
case *event.VerificationStartEventContent:
|
||||
mach.handleVerificationStart(evt.Sender, content, content.RelatesTo.EventID.String(), 10*time.Minute, evt.RoomID)
|
||||
case *event.VerificationReadyEventContent:
|
||||
mach.handleInRoomVerificationReady(evt.Sender, evt.RoomID, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationAcceptEventContent:
|
||||
mach.handleVerificationAccept(evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationKeyEventContent:
|
||||
mach.handleVerificationKey(evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationMacEventContent:
|
||||
mach.handleVerificationMAC(evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
case *event.VerificationCancelEventContent:
|
||||
mach.handleVerificationCancel(evt.Sender, content, content.RelatesTo.EventID.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationCancel is used to manually send an in-room SAS cancel message process with the given reason and cancellation code.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationCancel(roomID id.RoomID, userID id.UserID, transactionID string, reason string, code event.VerificationCancelCode) error {
|
||||
content := &event.VerificationCancelEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Reason: reason,
|
||||
Code: code,
|
||||
To: userID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(roomID, event.InRoomVerificationCancel, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationRequest is used to manually send an in-room SAS verification request message to another user.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationRequest(roomID id.RoomID, toUserID id.UserID, methods []VerificationMethod) (string, error) {
|
||||
content := &event.MessageEventContent{
|
||||
MsgType: event.MsgVerificationRequest,
|
||||
FromDevice: mach.Client.DeviceID,
|
||||
Methods: []event.VerificationMethod{event.VerificationMethodSAS},
|
||||
To: toUserID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(roomID, event.EventMessage, content)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
resp, err := mach.Client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return resp.EventID.String(), nil
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationReady is used to manually send an in-room SAS verification ready message to another user.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationReady(roomID id.RoomID, transactionID string) error {
|
||||
content := &event.VerificationReadyEventContent{
|
||||
FromDevice: mach.Client.DeviceID,
|
||||
Methods: []event.VerificationMethod{event.VerificationMethodSAS},
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(roomID, event.InRoomVerificationReady, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationStart is used to manually send the in-room SAS verification start message to another user.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationStart(roomID id.RoomID, toUserID id.UserID, transactionID string, methods []VerificationMethod) (*event.VerificationStartEventContent, error) {
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
}
|
||||
content := &event.VerificationStartEventContent{
|
||||
FromDevice: mach.Client.DeviceID,
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Method: event.VerificationMethodSAS,
|
||||
KeyAgreementProtocols: []event.KeyAgreementProtocol{event.KeyAgreementCurve25519HKDFSHA256},
|
||||
Hashes: []event.VerificationHashMethod{event.VerificationHashSHA256},
|
||||
MessageAuthenticationCodes: []event.MACMethod{event.HKDFHMACSHA256},
|
||||
ShortAuthenticationString: sasMethods,
|
||||
To: toUserID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(roomID, event.InRoomVerificationStart, content)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
|
||||
return content, err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationAccept is used to manually send an accept for an in-room SAS verification process from a received m.key.verification.start event.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationAccept(roomID id.RoomID, fromUser id.UserID, startEvent *event.VerificationStartEventContent, transactionID string, publicKey []byte, methods []VerificationMethod) error {
|
||||
if startEvent.Method != event.VerificationMethodSAS {
|
||||
reason := "Unknown verification method: " + string(startEvent.Method)
|
||||
if err := mach.SendInRoomSASVerificationCancel(roomID, fromUser, transactionID, reason, event.VerificationCancelUnknownMethod); err != nil {
|
||||
return err
|
||||
}
|
||||
return ErrUnknownVerificationMethod
|
||||
}
|
||||
payload, err := json.Marshal(startEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
canonical, err := canonicaljson.CanonicalJSON(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hash := olm.NewUtility().Sha256(string(publicKey) + string(canonical))
|
||||
sasMethods := make([]event.SASMethod, len(methods))
|
||||
for i, method := range methods {
|
||||
sasMethods[i] = method.Type()
|
||||
}
|
||||
content := &event.VerificationAcceptEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Method: event.VerificationMethodSAS,
|
||||
KeyAgreementProtocol: event.KeyAgreementCurve25519HKDFSHA256,
|
||||
Hash: event.VerificationHashSHA256,
|
||||
MessageAuthenticationCode: event.HKDFHMACSHA256,
|
||||
ShortAuthenticationString: sasMethods,
|
||||
Commitment: hash,
|
||||
To: fromUser,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(roomID, event.InRoomVerificationAccept, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationKey sends the ephemeral public key for a device to the partner device for an in-room verification.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationKey(roomID id.RoomID, userID id.UserID, transactionID string, key string) error {
|
||||
content := &event.VerificationKeyEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Key: key,
|
||||
To: userID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(roomID, event.InRoomVerificationKey, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// SendInRoomSASVerificationMAC sends the MAC of a device's key to the partner device for an in-room verification.
|
||||
func (mach *OlmMachine) SendInRoomSASVerificationMAC(roomID id.RoomID, userID id.UserID, deviceID id.DeviceID, transactionID string, sas *olm.SAS) error {
|
||||
keyID := id.NewKeyID(id.KeyAlgorithmEd25519, mach.Client.DeviceID.String())
|
||||
|
||||
signingKey := mach.account.SigningKey()
|
||||
keyIDsMap := map[id.KeyID]string{keyID: ""}
|
||||
macMap := make(map[id.KeyID]string)
|
||||
|
||||
if mach.CrossSigningKeys != nil {
|
||||
masterKey := mach.CrossSigningKeys.MasterKey.PublicKey
|
||||
masterKeyID := id.NewKeyID(id.KeyAlgorithmEd25519, masterKey.String())
|
||||
// add master key ID to key map
|
||||
keyIDsMap[masterKeyID] = ""
|
||||
masterKeyMAC, _, err := mach.getPKAndKeysMAC(sas, mach.Client.UserID, mach.Client.DeviceID,
|
||||
userID, deviceID, transactionID, masterKey, masterKeyID, keyIDsMap)
|
||||
if err != nil {
|
||||
mach.Log.Error("Error generating master key MAC: %v", err)
|
||||
} else {
|
||||
mach.Log.Debug("Generated master key `%v` MAC: %v", masterKey, masterKeyMAC)
|
||||
macMap[masterKeyID] = masterKeyMAC
|
||||
}
|
||||
}
|
||||
|
||||
pubKeyMac, keysMac, err := mach.getPKAndKeysMAC(sas, mach.Client.UserID, mach.Client.DeviceID, userID, deviceID, transactionID, signingKey, keyID, keyIDsMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mach.Log.Debug("MAC of key %s is: %s", signingKey, pubKeyMac)
|
||||
mach.Log.Debug("MAC of key ID(s) %s is: %s", keyID, keysMac)
|
||||
macMap[keyID] = pubKeyMac
|
||||
|
||||
content := &event.VerificationMacEventContent{
|
||||
RelatesTo: &event.RelatesTo{Type: event.RelReference, EventID: id.EventID(transactionID)},
|
||||
Keys: keysMac,
|
||||
Mac: macMap,
|
||||
To: userID,
|
||||
}
|
||||
|
||||
encrypted, err := mach.EncryptMegolmEvent(roomID, event.InRoomVerificationMAC, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = mach.Client.SendMessageEvent(roomID, event.EventEncrypted, encrypted)
|
||||
return err
|
||||
}
|
||||
|
||||
// NewInRoomSASVerificationWith starts the in-room SAS verification process with another user in the given room.
|
||||
// It returns the generated transaction ID.
|
||||
func (mach *OlmMachine) NewInRoomSASVerificationWith(inRoomID id.RoomID, userID id.UserID, hooks VerificationHooks, timeout time.Duration) (string, error) {
|
||||
return mach.newInRoomSASVerificationWithInner(inRoomID, &id.Device{UserID: userID}, hooks, "", timeout)
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) newInRoomSASVerificationWithInner(inRoomID id.RoomID, device *id.Device, hooks VerificationHooks, transactionID string, timeout time.Duration) (string, error) {
|
||||
mach.Log.Debug("Starting new in-room verification transaction user %v", device.UserID)
|
||||
|
||||
request := transactionID == ""
|
||||
if request {
|
||||
var err error
|
||||
// get new transaction ID from the request message event ID
|
||||
transactionID, err = mach.SendInRoomSASVerificationRequest(inRoomID, device.UserID, hooks.VerificationMethods())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
verState := &verificationState{
|
||||
sas: olm.NewSAS(),
|
||||
otherDevice: device,
|
||||
initiatedByUs: true,
|
||||
verificationStarted: false,
|
||||
keyReceived: false,
|
||||
sasMatched: make(chan bool, 1),
|
||||
hooks: hooks,
|
||||
inRoomID: inRoomID,
|
||||
}
|
||||
verState.lock.Lock()
|
||||
defer verState.lock.Unlock()
|
||||
|
||||
if !request {
|
||||
// start in-room verification
|
||||
startEvent, err := mach.SendInRoomSASVerificationStart(inRoomID, device.UserID, transactionID, hooks.VerificationMethods())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
payload, err := json.Marshal(startEvent)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
canonical, err := canonicaljson.CanonicalJSON(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
verState.startEventCanonical = string(canonical)
|
||||
}
|
||||
|
||||
mach.keyVerificationTransactionState.Store(device.UserID.String()+":"+transactionID, verState)
|
||||
|
||||
mach.timeoutAfter(verState, transactionID, timeout)
|
||||
|
||||
return transactionID, nil
|
||||
}
|
||||
|
||||
func (mach *OlmMachine) handleInRoomVerificationReady(userID id.UserID, roomID id.RoomID, content *event.VerificationReadyEventContent, transactionID string) {
|
||||
device, err := mach.GetOrFetchDevice(userID, content.FromDevice)
|
||||
if err != nil {
|
||||
mach.Log.Error("Error fetching device %v of user %v: %v", content.FromDevice, userID, err)
|
||||
return
|
||||
}
|
||||
|
||||
verState, err := mach.getTransactionState(transactionID, userID)
|
||||
if err != nil {
|
||||
mach.Log.Error("Error getting transaction state: %v", err)
|
||||
return
|
||||
}
|
||||
//mach.keyVerificationTransactionState.Delete(userID.String() + ":" + transactionID)
|
||||
|
||||
if mach.Client.UserID < userID {
|
||||
// up to us to send the start message
|
||||
verState.lock.Lock()
|
||||
mach.newInRoomSASVerificationWithInner(roomID, device, verState.hooks, transactionID, 10*time.Minute)
|
||||
verState.lock.Unlock()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user