// Copyright (c) 2020 Nikos Filippakis // Copyright (c) 2023 Tulir Asokan // // 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 ( "context" "maunium.net/go/mautrix/id" ) func (mach *OlmMachine) ResolveTrust(device *id.Device) id.TrustState { state, _ := mach.ResolveTrustContext(context.Background(), device) return state } // ResolveTrustContext resolves the trust state of the device from cross-signing. func (mach *OlmMachine) ResolveTrustContext(ctx context.Context, device *id.Device) (id.TrustState, error) { if device.Trust == id.TrustStateVerified || device.Trust == id.TrustStateBlacklisted { return device.Trust, nil } theirKeys, err := mach.CryptoStore.GetCrossSigningKeys(device.UserID) if err != nil { mach.machOrContextLog(ctx).Error().Err(err). Str("user_id", device.UserID.String()). Msg("Error retrieving cross-signing key of user from database") return id.TrustStateUnset, err } theirMSK, ok := theirKeys[id.XSUsageMaster] if !ok { mach.machOrContextLog(ctx).Error(). Str("user_id", device.UserID.String()). Msg("Master key of user not found") return id.TrustStateUnset, nil } theirSSK, ok := theirKeys[id.XSUsageSelfSigning] if !ok { mach.machOrContextLog(ctx).Error(). Str("user_id", device.UserID.String()). Msg("Self-signing key of user not found") return id.TrustStateUnset, nil } sskSigExists, err := mach.CryptoStore.IsKeySignedBy(device.UserID, theirSSK.Key, device.UserID, theirMSK.Key) if err != nil { mach.machOrContextLog(ctx).Error().Err(err). Str("user_id", device.UserID.String()). Msg("Error retrieving cross-signing signatures for master key of user from database") return id.TrustStateUnset, err } if !sskSigExists { mach.machOrContextLog(ctx).Error(). Str("user_id", device.UserID.String()). Msg("Self-signing key of user is not signed by their master key") return id.TrustStateUnset, nil } deviceSigExists, err := mach.CryptoStore.IsKeySignedBy(device.UserID, device.SigningKey, device.UserID, theirSSK.Key) if err != nil { mach.machOrContextLog(ctx).Error().Err(err). Str("user_id", device.UserID.String()). Str("device_key", device.SigningKey.String()). Msg("Error retrieving cross-signing signatures for device from database") return id.TrustStateUnset, err } if deviceSigExists { if trusted, err := mach.IsUserTrusted(ctx, device.UserID); !trusted { return id.TrustStateCrossSignedVerified, err } else if theirMSK.Key == theirMSK.First { return id.TrustStateCrossSignedTOFU, nil } return id.TrustStateCrossSignedUntrusted, nil } return id.TrustStateUnset, nil } // IsDeviceTrusted returns whether a device has been determined to be trusted either through verification or cross-signing. func (mach *OlmMachine) IsDeviceTrusted(device *id.Device) bool { switch mach.ResolveTrust(device) { case id.TrustStateVerified, id.TrustStateCrossSignedTOFU, id.TrustStateCrossSignedVerified: return true default: return false } } // IsUserTrusted returns whether a user has been determined to be trusted by our user-signing key having signed their master key. // In the case the user ID is our own and we have successfully retrieved our cross-signing keys, we trust our own user. func (mach *OlmMachine) IsUserTrusted(ctx context.Context, userID id.UserID) (bool, error) { csPubkeys := mach.GetOwnCrossSigningPublicKeys() if csPubkeys == nil { return false, nil } if userID == mach.Client.UserID { return true, nil } // first we verify our user-signing key ourUserSigningKeyTrusted, err := mach.CryptoStore.IsKeySignedBy(mach.Client.UserID, csPubkeys.UserSigningKey, mach.Client.UserID, csPubkeys.MasterKey) if err != nil { mach.machOrContextLog(ctx).Error().Err(err).Msg("Error retrieving our self-signing key signatures from database") return false, err } else if !ourUserSigningKeyTrusted { return false, nil } theirKeys, err := mach.CryptoStore.GetCrossSigningKeys(userID) if err != nil { mach.machOrContextLog(ctx).Error().Err(err). Str("user_id", userID.String()). Msg("Error retrieving cross-signing key of user from database") return false, err } theirMskKey, ok := theirKeys[id.XSUsageMaster] if !ok { mach.machOrContextLog(ctx).Error(). Str("user_id", userID.String()). Msg("Master key of user not found") return false, nil } sigExists, err := mach.CryptoStore.IsKeySignedBy(userID, theirMskKey.Key, mach.Client.UserID, csPubkeys.UserSigningKey) if err != nil { mach.machOrContextLog(ctx).Error().Err(err). Str("user_id", userID.String()). Msg("Error retrieving cross-signing signatures for master key of user from database") return false, err } return sigExists, nil }