diff --git a/library/rustCrypto/matrix-rust-sdk-crypto.aar b/library/rustCrypto/matrix-rust-sdk-crypto.aar index 2b7a3a32e8..5a5cef7d0f 100644 --- a/library/rustCrypto/matrix-rust-sdk-crypto.aar +++ b/library/rustCrypto/matrix-rust-sdk-crypto.aar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a5b58eecbbaa8354901a57c7df727eb2ad6e401dd286ecf049d7a438788ac6ef -size 16077430 +oid sha256:755bd2766aa1f317722c60259faf9759b9049885f20b91ed2a4dcfbcba861bfc +size 17402892 diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt index 8dde36cfec..078a458e87 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt @@ -23,7 +23,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.flow.cancellable -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch import org.amshove.kluent.fail import org.junit.Assert.assertEquals diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt index faee85678e..47cc8be31e 100644 --- a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt @@ -16,7 +16,6 @@ package org.matrix.android.sdk.internal.crypto -import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult @@ -63,7 +62,7 @@ internal class DecryptRoomEventUseCase @Inject constructor( claimedEd25519Key = olmDecryptionResult.keysClaimed?.get("ed25519"), forwardingCurve25519KeyChain = olmDecryptionResult.forwardingCurve25519KeyChain .orEmpty(), - isSafe = olmDecryptionResult.isSafe.orFalse() + messageVerificationState = olmDecryptionResult.verificationState ) } else { throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON) @@ -139,7 +138,7 @@ internal class DecryptRoomEventUseCase @Inject constructor( senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) } } diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt index 03672ae81c..79acfa25dc 100644 --- a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/EventDecryptor.kt @@ -103,7 +103,7 @@ internal class EventDecryptor @Inject constructor( senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) } } diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt index faadf339e9..d970028b11 100755 --- a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/MXOlmDevice.kt @@ -23,11 +23,15 @@ import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.crypto.MXCryptoError +import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.api.session.crypto.model.MessageVerificationState import org.matrix.android.sdk.api.session.crypto.model.OlmDecryptionResult import org.matrix.android.sdk.api.util.JSON_DICT_PARAMETERIZED_TYPE import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.crypto.algorithms.megolm.MXOutboundSessionInfo import org.matrix.android.sdk.internal.crypto.algorithms.megolm.SharedWithHelper +import org.matrix.android.sdk.internal.crypto.crosssigning.CrossSigningOlm +import org.matrix.android.sdk.internal.crypto.crosssigning.canonicalSignable import org.matrix.android.sdk.internal.crypto.model.InboundGroupSessionData import org.matrix.android.sdk.internal.crypto.model.MXInboundMegolmSessionWrapper import org.matrix.android.sdk.internal.crypto.model.OlmSessionWrapper @@ -59,6 +63,7 @@ internal class MXOlmDevice @Inject constructor( private val store: IMXCryptoStore, private val olmSessionStore: OlmSessionStore, private val inboundGroupSessionStore: InboundGroupSessionStore, + private val crossSigningOlm: CrossSigningOlm, private val clock: Clock, ) { @@ -851,15 +856,60 @@ internal class MXOlmDevice @Inject constructor( throw MXCryptoError.Base(MXCryptoError.ErrorType.BAD_DECRYPTED_FORMAT, MXCryptoError.BAD_DECRYPTED_FORMAT_TEXT_REASON) } + val verificationState = if (sessionHolder.wrapper.sessionData.trusted.orFalse()) { + // let's get info on the device + val sendingDevice = store.deviceWithIdentityKey(senderKey) + if (sendingDevice == null) { + MessageVerificationState.UNKNOWN_DEVICE + } else { + val isDeviceOwnerOfSession = sessionHolder.wrapper.sessionData.keysClaimed?.get("ed25519") == sendingDevice.fingerprint() + if (!isDeviceOwnerOfSession) { + MessageVerificationState.MISMATCH + } else if (sendingDevice.isVerified) { + MessageVerificationState.VERIFIED + } else { + val isDeviceOwnerVerified = store.getCrossSigningInfo(sendingDevice.userId)?.isTrusted() ?: false + val isDeviceSignedByItsOwner = isDeviceSignByItsOwner(sendingDevice) + if (isDeviceSignedByItsOwner) { + if (isDeviceOwnerVerified) MessageVerificationState.VERIFIED + else MessageVerificationState.SIGNED_DEVICE_OF_UNVERIFIED_USER + } else { + if (isDeviceOwnerVerified) MessageVerificationState.UN_SIGNED_DEVICE_OF_VERIFIED_USER + else MessageVerificationState.UN_SIGNED_DEVICE + } + } + } + } else { + MessageVerificationState.UNSAFE_SOURCE + } return OlmDecryptionResult( payload, wrapper.sessionData.keysClaimed, senderKey, wrapper.sessionData.forwardingCurve25519KeyChain, - isSafe = sessionHolder.wrapper.sessionData.trusted.orFalse() + isSafe = sessionHolder.wrapper.sessionData.trusted.orFalse(), + verificationState = verificationState, ) } + private fun isDeviceSignByItsOwner(device: CryptoDeviceInfo): Boolean { + val otherKeys = store.getCrossSigningInfo(device.userId) ?: return false + val otherSSKSignature = device.signatures?.get(device.userId)?.get("ed25519:${otherKeys.selfSigningKey()?.unpaddedBase64PublicKey}") + ?: return false + + // Check bob's device is signed by bob's SSK + try { + crossSigningOlm.olmUtility.verifyEd25519Signature( + otherSSKSignature, + otherKeys.selfSigningKey()?.unpaddedBase64PublicKey, + device.canonicalSignable() + ) + return true + } catch (e: Throwable) { + return false + } + } + /** * Reset replay attack data for the given timeline. * diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt index 125068ce83..8721374244 100644 --- a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/crypto/algorithms/megolm/MXMegolmDecryption.kt @@ -18,7 +18,6 @@ package org.matrix.android.sdk.internal.crypto.algorithms.megolm import dagger.Lazy import org.matrix.android.sdk.api.crypto.MXCryptoConfig -import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.crypto.MXCryptoError import org.matrix.android.sdk.api.session.crypto.NewSessionListener @@ -100,7 +99,7 @@ internal class MXMegolmDecryption( claimedEd25519Key = olmDecryptionResult.keysClaimed?.get("ed25519"), forwardingCurve25519KeyChain = olmDecryptionResult.forwardingCurve25519KeyChain .orEmpty(), - isSafe = olmDecryptionResult.isSafe.orFalse() + messageVerificationState = olmDecryptionResult.verificationState, ).also { liveEventManager.get().dispatchLiveEventDecrypted(event, it) } diff --git a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt index aa301d5d6e..f3e5180b93 100644 --- a/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt +++ b/matrix-sdk-android/src/kotlinCrypto/java/org/matrix/android/sdk/internal/session/sync/handler/CryptoSyncHandler.kt @@ -114,7 +114,7 @@ internal class CryptoSyncHandler @Inject constructor( senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState, ) return true } else { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEventDecryptionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEventDecryptionResult.kt index 66d7558fe2..7ddbe18d04 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEventDecryptionResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/MXEventDecryptionResult.kt @@ -18,6 +18,16 @@ package org.matrix.android.sdk.api.session.crypto.model import org.matrix.android.sdk.api.util.JsonDict +enum class MessageVerificationState { + VERIFIED, + SIGNED_DEVICE_OF_UNVERIFIED_USER, + UN_SIGNED_DEVICE_OF_VERIFIED_USER, + UN_SIGNED_DEVICE, + UNKNOWN_DEVICE, + UNSAFE_SOURCE, + MISMATCH, +} + /** * The result of a (successful) call to decryptEvent. */ @@ -45,5 +55,5 @@ data class MXEventDecryptionResult( */ val forwardingCurve25519KeyChain: List = emptyList(), - val isSafe: Boolean = false + val messageVerificationState: MessageVerificationState? = null, ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt index 6d57318f87..116c0a7a3c 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/model/OlmDecryptionResult.kt @@ -22,6 +22,7 @@ import org.matrix.android.sdk.api.util.JsonDict /** * This class represents the decryption result. + * It's serialized in eventEntity to remember the decryption result */ @JsonClass(generateAdapter = true) data class OlmDecryptionResult( @@ -50,4 +51,9 @@ data class OlmDecryptionResult( * True if the key used to decrypt is considered safe (trusted). */ @Json(name = "key_safety") val isSafe: Boolean? = null, + + /** + * Authenticity info for that message + */ + @Json(name = "verification_state") val verificationState: MessageVerificationState? = null, ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt index 774924fc7d..2f132fc1ad 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/crypto/verification/VerificationTransaction.kt @@ -1,5 +1,5 @@ /* - * Copyright 2020 The Matrix.org Foundation C.I.C. + * Copyright (c) 2023 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. @@ -16,8 +16,6 @@ package org.matrix.android.sdk.api.session.crypto.verification -import org.matrix.android.sdk.internal.crypto.verification.qrcode.QrCodeVerification - interface VerificationTransaction { val method: VerificationMethod @@ -44,7 +42,7 @@ interface VerificationTransaction { internal fun VerificationTransaction.dbgState(): String? { return when (this) { is SasVerificationTransaction -> "${this.state()}" - is QrCodeVerification -> "${this.state()}" + is QrCodeVerificationTransaction -> "${this.state()}" else -> "??" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt index b34a6056b6..0f5f9f64cc 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/tasks/EncryptEventTask.kt @@ -19,6 +19,7 @@ import dagger.Lazy import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM import org.matrix.android.sdk.api.session.crypto.CryptoService import org.matrix.android.sdk.api.session.crypto.model.MXEventDecryptionResult +import org.matrix.android.sdk.api.session.crypto.model.MessageVerificationState import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType import org.matrix.android.sdk.api.session.events.model.toContent @@ -78,7 +79,7 @@ internal class DefaultEncryptEventTask @Inject constructor( forwardingCurve25519KeyChain = emptyList(), senderCurve25519Key = result.eventContent["sender_key"] as? String, claimedEd25519Key = cryptoService.get().getMyCryptoDevice().fingerprint(), - isSafe = true + messageVerificationState = MessageVerificationState.VERIFIED ) } else { null diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt index 908c710df4..2114250518 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/helper/ThreadSummaryHelper.kt @@ -210,7 +210,7 @@ private fun decryptIfNeeded(cryptoService: CryptoService?, eventEntity: EventEnt senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) // Save decryption result, to not decrypt every time we enter the thread list eventEntity.setDecryptionResult(result) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt index ee5c3d90c1..9574e443ad 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/model/EventEntity.kt @@ -88,7 +88,7 @@ internal open class EventEntity( senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) val adapter = MoshiProvider.providesMoshi().adapter(OlmDecryptionResult::class.java) decryptionResultJson = adapter.toJson(decryptionResult) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt index 019f859b76..f129ce9034 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/relation/threads/FetchThreadTimelineTask.kt @@ -251,7 +251,7 @@ internal class DefaultFetchThreadTimelineTask @Inject constructor( senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) } catch (e: MXCryptoError) { if (e is MXCryptoError.Base) { diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt index 044ce51a62..75f62009ea 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncResponseHandler.kt @@ -139,14 +139,13 @@ internal class SyncResponseHandler @Inject constructor( try { val timelineId = generateTimelineId(roomId) // Event from sync does not have roomId, so add it to the event first - // note: runBlocking should be used here while we are in realm single thread executor, to avoid thread switching val result = cryptoService.decryptEvent(event.copy(roomId = roomId), timelineId) event.mxDecryptionResult = OlmDecryptionResult( payload = result.clearEvent, senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) } catch (e: MXCryptoError) { Timber.v(e, "Failed to decrypt $roomId") diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt index 4737862b5b..948a0a2501 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/SyncResponsePostTreatmentAggregatorHandler.kt @@ -105,7 +105,7 @@ internal class SyncResponsePostTreatmentAggregatorHandler @Inject constructor( .enqueue() } - private fun handleUserIdsForCheckingTrustAndAffectedRoomShields(userIdsWithDeviceUpdate: Collection) { + private suspend fun handleUserIdsForCheckingTrustAndAffectedRoomShields(userIdsWithDeviceUpdate: Collection) { if (userIdsWithDeviceUpdate.isEmpty()) return crossSigningService.checkTrustAndAffectedRoomShields(userIdsWithDeviceUpdate.toList()) } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt index cacacd232c..177f17a0d5 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/DecryptRoomEventUseCase.kt @@ -38,7 +38,7 @@ internal class DecryptRoomEventUseCase @Inject constructor(private val olmMachin senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) } } diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt index 36e0dcdd8f..5f40bee3da 100644 --- a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/OlmMachine.kt @@ -73,7 +73,6 @@ import org.matrix.rustcomponents.sdk.crypto.DecryptionException import org.matrix.rustcomponents.sdk.crypto.DeviceLists import org.matrix.rustcomponents.sdk.crypto.EncryptionSettings import org.matrix.rustcomponents.sdk.crypto.KeyRequestPair -import org.matrix.rustcomponents.sdk.crypto.KeySafety import org.matrix.rustcomponents.sdk.crypto.KeysImportResult import org.matrix.rustcomponents.sdk.crypto.Logger import org.matrix.rustcomponents.sdk.crypto.MegolmV1BackupKey @@ -431,7 +430,7 @@ internal class OlmMachine @Inject constructor( throw MXCryptoError.Base(MXCryptoError.ErrorType.MISSING_FIELDS, MXCryptoError.MISSING_FIELDS_REASON) } val serializedEvent = adapter.toJson(event) - val decrypted = inner.decryptRoomEvent(serializedEvent, event.roomId) + val decrypted = inner.decryptRoomEvent(serializedEvent, event.roomId, false) val deserializationAdapter = moshi.adapter(Map::class.java) @@ -443,7 +442,7 @@ internal class OlmMachine @Inject constructor( senderCurve25519Key = decrypted.senderCurve25519Key, claimedEd25519Key = decrypted.claimedEd25519Key, forwardingCurve25519KeyChain = decrypted.forwardingCurve25519Chain, - isSafe = decrypted.keySafety == KeySafety.SAFE, + messageVerificationState = decrypted.verificationState.fromInner(), ) } catch (throwable: Throwable) { val reThrow = when (throwable) { diff --git a/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustExt.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustExt.kt new file mode 100644 index 0000000000..54e059b08b --- /dev/null +++ b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/RustExt.kt @@ -0,0 +1,32 @@ +/* + * Copyright 2023 The Matrix.org Foundation C.I.C. + * + * 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 org.matrix.android.sdk.internal.crypto + +import org.matrix.android.sdk.api.session.crypto.model.MessageVerificationState +import org.matrix.rustcomponents.sdk.crypto.VerificationState as InnerVerificationState + +fun InnerVerificationState.fromInner(): MessageVerificationState { + return when (this) { + InnerVerificationState.VERIFIED -> MessageVerificationState.VERIFIED + InnerVerificationState.SIGNED_DEVICE_OF_UNVERIFIED_USER -> MessageVerificationState.SIGNED_DEVICE_OF_UNVERIFIED_USER + InnerVerificationState.UN_SIGNED_DEVICE_OF_VERIFIED_USER -> MessageVerificationState.UN_SIGNED_DEVICE_OF_VERIFIED_USER + InnerVerificationState.UN_SIGNED_DEVICE -> MessageVerificationState.UN_SIGNED_DEVICE + InnerVerificationState.UNKNOWN_DEVICE -> MessageVerificationState.UNKNOWN_DEVICE + InnerVerificationState.UNSAFE_SOURCE -> MessageVerificationState.UNSAFE_SOURCE + InnerVerificationState.MISMATCH -> MessageVerificationState.MISMATCH + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt b/matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt similarity index 100% rename from matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt rename to matrix-sdk-android/src/rustCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationListenersHolder.kt diff --git a/matrix-sdk-android/src/testKotlinCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationActorTest.kt b/matrix-sdk-android/src/testKotlinCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationActorTest.kt index 496ec60688..364a3047ed 100644 --- a/matrix-sdk-android/src/testKotlinCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationActorTest.kt +++ b/matrix-sdk-android/src/testKotlinCrypto/java/org/matrix/android/sdk/internal/crypto/verification/VerificationActorTest.kt @@ -30,7 +30,6 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt index ca93c1389e..2083fd6038 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/edithistory/ViewEditHistoryViewModel.kt @@ -84,7 +84,7 @@ class ViewEditHistoryViewModel @AssistedInject constructor( senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { k -> mapOf("ed25519" to k) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) } catch (e: MXCryptoError) { Timber.w("Failed to decrypt event in history") diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt index 0fc07ef0e1..e489f4324b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/helper/MessageInformationDataFactory.kt @@ -29,6 +29,7 @@ import im.vector.app.features.home.room.detail.timeline.style.TimelineMessageLay import kotlinx.coroutines.runBlocking import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.api.session.crypto.model.MessageVerificationState import org.matrix.android.sdk.api.session.crypto.verification.VerificationState import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.EventType @@ -74,9 +75,10 @@ class MessageInformationDataFactory @Inject constructor( prevDisplayableEvent?.root?.localDateTime()?.toLocalDate() != date.toLocalDate() val time = dateFormatter.format(event.root.originServerTs, DateFormatKind.MESSAGE_SIMPLE) - val e2eDecoration = runBlocking { - getE2EDecoration(roomSummary, params.lastEdit ?: event.root) - } +// val e2eDecoration = runBlocking { +// getE2EDecoration(roomSummary, params.lastEdit ?: event.root) +// } + val e2eDecoration = getE2EDecorationV2(roomSummary, params.lastEdit ?: event.root) val senderId = runBlocking { getSenderId(event) } // SendState Decoration val sendStateDecoration = if (isSentByMe) { @@ -147,6 +149,47 @@ class MessageInformationDataFactory @Inject constructor( } } + private fun getE2EDecorationV2(roomSummary: RoomSummary?, event: Event): E2EDecoration { + if (roomSummary?.isEncrypted != true) { + // No decoration for clear room + // Questionable? what if the event is E2E? + return E2EDecoration.NONE + } + if (event.sendState != SendState.SYNCED) { + // we don't display e2e decoration if event not synced back + return E2EDecoration.NONE + } + + return when (event.mxDecryptionResult?.verificationState) { + MessageVerificationState.VERIFIED -> E2EDecoration.NONE + MessageVerificationState.SIGNED_DEVICE_OF_UNVERIFIED_USER -> E2EDecoration.NONE + MessageVerificationState.UN_SIGNED_DEVICE_OF_VERIFIED_USER -> E2EDecoration.WARN_SENT_BY_UNVERIFIED + // We neither verified this user so not interesting in that warning? + MessageVerificationState.UN_SIGNED_DEVICE -> E2EDecoration.NONE + MessageVerificationState.UNKNOWN_DEVICE -> E2EDecoration.WARN_SENT_BY_DELETED_SESSION + MessageVerificationState.UNSAFE_SOURCE -> E2EDecoration.WARN_UNSAFE_KEY + MessageVerificationState.MISMATCH -> E2EDecoration.WARN_UNSAFE_KEY + null -> { + // No verification state. + // So could be a clear event, or a legacy decryption, or an UTD event + if (!event.isEncrypted()) { + e2EDecorationForClearEventInE2ERoom(event, roomSummary) + } else if (event.mxDecryptionResult != null) { + // No verification state, so could be a migrated old decryption? + if (event.mxDecryptionResult?.isSafe == true) { + // for past legacy decryption let's not decorate + E2EDecoration.NONE + } else { + E2EDecoration.WARN_UNSAFE_KEY + } + } else { + // Undecrypted event + E2EDecoration.NONE + } + } + } + } + private suspend fun getE2EDecoration(roomSummary: RoomSummary?, event: Event): E2EDecoration { if (roomSummary?.isEncrypted != true) { // No decoration for clear room diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt index 988ab01ef8..f71d3ad229 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotifiableEventResolver.kt @@ -217,7 +217,7 @@ class NotifiableEventResolver @Inject constructor( senderKey = result.senderCurve25519Key, keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) }, forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain, - isSafe = result.isSafe + verificationState = result.messageVerificationState ) } catch (ignore: MXCryptoError) { }