From ff95392e10b4252f7bbc531616419c89fcca64c2 Mon Sep 17 00:00:00 2001 From: Valere Date: Thu, 30 Jan 2020 16:10:59 +0100 Subject: [PATCH] Fix / Refresh trust state on own keys/device trust change --- .../DefaultCrossSigningService.kt | 34 ++++++++- .../internal/crypto/store/IMXCryptoStore.kt | 2 + .../crypto/store/db/RealmCryptoStore.kt | 70 ++++++++++++++----- .../verification/VerificationInfoRequest.kt | 36 ++++++++++ 4 files changed, 120 insertions(+), 22 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationInfoRequest.kt diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/DefaultCrossSigningService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/DefaultCrossSigningService.kt index 1208035fd0..0c13daf560 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/DefaultCrossSigningService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/crosssigning/DefaultCrossSigningService.kt @@ -114,7 +114,7 @@ internal class DefaultCrossSigningService @Inject constructor( } // Recover local trust in case private key are there? - cryptoStore.setUserKeysAsTrusted(userId, checkUserTrust(userId).isVerified()) + setUserKeysAsTrusted(userId, checkUserTrust(userId).isVerified()) } } catch (e: Throwable) { // Mmm this kind of a big issue @@ -205,7 +205,7 @@ internal class DefaultCrossSigningService @Inject constructor( val crossSigningInfo = MXCrossSigningInfo(userId, listOf(params.masterKey, params.userKey, params.selfSignedKey)) cryptoStore.setMyCrossSigningInfo(crossSigningInfo) - cryptoStore.setUserKeysAsTrusted(userId) + setUserKeysAsTrusted(userId, true) cryptoStore.storePrivateKeysInfo(masterKeyPrivateKey?.toBase64NoPadding(), uskPrivateKey?.toBase64NoPadding(), sskPrivateKey?.toBase64NoPadding()) uploadSigningKeysTask.configureWith(params) { @@ -615,7 +615,7 @@ internal class DefaultCrossSigningService @Inject constructor( checkUserTrust(otherUserId).let { Timber.d("## CrossSigning - update trust for $otherUserId , verified=${it.isVerified()}") - cryptoStore.setUserKeysAsTrusted(otherUserId, it.isVerified()) + setUserKeysAsTrusted(otherUserId, it.isVerified()) } // TODO if my keys have changes, i should recheck all devices of all users? @@ -625,6 +625,34 @@ internal class DefaultCrossSigningService @Inject constructor( Timber.d("## CrossSigning - update trust for device ${device.deviceId} of user $otherUserId , verified=$updatedTrust") cryptoStore.setDeviceTrust(otherUserId, device.deviceId, updatedTrust.isCrossSignedVerified(), updatedTrust.isLocallyVerified()) } + + if (otherUserId == userId) { + // It's me, i should check if a newly trusted device is signing my master key + // In this case it will change my MSK trust, and should then re-trigger a check of all other user trust + setUserKeysAsTrusted(otherUserId, checkSelfTrust().isVerified()) + } + } + } + + private fun setUserKeysAsTrusted(otherUserId: String, trusted: Boolean) { + val currentTrust = cryptoStore.getCrossSigningInfo(otherUserId)?.isTrusted() + cryptoStore.setUserKeysAsTrusted(otherUserId, trusted) + + // If it's me, recheck trust of all users and devices? + val users = ArrayList() + if (otherUserId == userId && currentTrust != trusted) { + cryptoStore.updateUsersTrust { + users.add(it) + checkUserTrust(it).isVerified() + } + + users.forEach { + cryptoStore.getUserDeviceList(it)?.forEach { device -> + val updatedTrust = checkDeviceTrust(it, device.deviceId, device.trustLevel?.isLocallyVerified() ?: false) + Timber.d("## CrossSigning - update trust for device ${device.deviceId} of user $otherUserId , verified=$updatedTrust") + cryptoStore.setDeviceTrust(it, device.deviceId, updatedTrust.isCrossSignedVerified(), updatedTrust.isLocallyVerified()) + } + } } } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt index a82ca8217d..022e1ba320 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/IMXCryptoStore.kt @@ -414,4 +414,6 @@ internal interface IMXCryptoStore { fun setDeviceTrust(userId: String, deviceId: String, crossSignedVerified: Boolean, locallyVerified : Boolean) fun clearOtherUserTrust() + + fun updateUsersTrust(check: (String) -> Boolean) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt index 7fa7c47a1e..21e52cf1b9 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/store/db/RealmCryptoStore.kt @@ -962,34 +962,66 @@ internal class RealmCryptoStore(private val realmConfiguration: RealmConfigurati } } + override fun updateUsersTrust(check: (String) -> Boolean) { + doRealmTransaction(realmConfiguration) { realm -> + val xInfoEntities = realm.where(CrossSigningInfoEntity::class.java) + .findAll() + xInfoEntities?.forEach { xInfoEntity -> + // Need to ignore mine + if (xInfoEntity.userId == credentials.userId) return@forEach + val mapped = mapCrossSigningInfoEntity(xInfoEntity) + val currentTrust = mapped.isTrusted() + val newTrust = check(mapped.userId) + if (currentTrust != newTrust) { + xInfoEntity.crossSigningKeys.forEach { info -> + val level = info.trustLevelEntity + if (level == null) { + val newLevel = realm.createObject(TrustLevelEntity::class.java) + newLevel.locallyVerified = newTrust + newLevel.crossSignedVerified = newTrust + info.trustLevelEntity = newLevel + } else { + level.locallyVerified = newTrust + level.crossSignedVerified = newTrust + } + } + } + } + } + } + override fun getCrossSigningInfo(userId: String): MXCrossSigningInfo? { return doRealmQueryAndCopy(realmConfiguration) { realm -> realm.where(CrossSigningInfoEntity::class.java) .equalTo(CrossSigningInfoEntityFields.USER_ID, userId) .findFirst() }?.let { xsignInfo -> - MXCrossSigningInfo( - userId = userId, - crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull { - val pubKey = it.publicKeyBase64 ?: return@mapNotNull null - CryptoCrossSigningKey( - userId = userId, - keys = mapOf("ed25519:$pubKey" to pubKey), - usages = it.usages.map { it }, - signatures = it.getSignatures(), - trustLevel = it.trustLevelEntity?.let { - DeviceTrustLevel( - crossSigningVerified = it.crossSignedVerified ?: false, - locallyVerified = it.locallyVerified ?: false - ) - } - - ) - } - ) + mapCrossSigningInfoEntity(xsignInfo) } } + private fun mapCrossSigningInfoEntity(xsignInfo: CrossSigningInfoEntity): MXCrossSigningInfo { + return MXCrossSigningInfo( + userId = xsignInfo.userId ?: "", + crossSigningKeys = xsignInfo.crossSigningKeys.mapNotNull { + val pubKey = it.publicKeyBase64 ?: return@mapNotNull null + CryptoCrossSigningKey( + userId = xsignInfo.userId ?: "", + keys = mapOf("ed25519:$pubKey" to pubKey), + usages = it.usages.map { it }, + signatures = it.getSignatures(), + trustLevel = it.trustLevelEntity?.let { + DeviceTrustLevel( + crossSigningVerified = it.crossSignedVerified ?: false, + locallyVerified = it.locallyVerified ?: false + ) + } + + ) + } + ) + } + override fun getLiveCrossSigningInfo(userId: String): LiveData> { val liveData = monarchy.findAllMappedWithChanges( { realm: Realm -> diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationInfoRequest.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationInfoRequest.kt new file mode 100644 index 0000000000..529334c3ea --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/VerificationInfoRequest.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.matrix.android.internal.crypto.verification + +interface VerificationInfoRequest : VerificationInfo { + + /** + * Required. The device ID which is initiating the request. + */ + val fromDevice: String? + + /** + * Required. The verification methods supported by the sender. + */ + val methods: List? + + /** + * The POSIX timestamp in milliseconds for when the request was made. + * If the request is in the future by more than 5 minutes or more than 10 minutes in the past, + * the message should be ignored by the receiver. + */ + val timestamp: Long? +}