diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CommonTestHelper.kt index 08c81f56c0..413e4aac3c 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/common/CommonTestHelper.kt @@ -266,8 +266,8 @@ class CommonTestHelper(context: Context) { * @param latch * @throws InterruptedException */ - fun await(latch: CountDownLatch) { - assertTrue(latch.await(TestConstants.timeOutMillis, TimeUnit.MILLISECONDS)) + fun await(latch: CountDownLatch, timout: Long? = TestConstants.timeOutMillis) { + assertTrue(latch.await(timout ?: TestConstants.timeOutMillis, TimeUnit.MILLISECONDS)) } fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) { diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt index c8d2df38ce..da8ef790ab 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/internal/crypto/gossiping/KeyShareTests.kt @@ -19,6 +19,12 @@ package im.vector.matrix.android.internal.crypto.gossiping import android.util.Log import androidx.test.ext.junit.runners.AndroidJUnit4 import im.vector.matrix.android.InstrumentedTest +import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerificationTransaction +import im.vector.matrix.android.api.session.crypto.verification.SasVerificationTransaction +import im.vector.matrix.android.api.session.crypto.verification.VerificationMethod +import im.vector.matrix.android.api.session.crypto.verification.VerificationService +import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction +import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.RoomDirectoryVisibility import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams @@ -28,7 +34,11 @@ import im.vector.matrix.android.common.TestConstants import im.vector.matrix.android.internal.crypto.GossipingRequestState import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestState import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel +import im.vector.matrix.android.internal.crypto.model.CryptoDeviceInfo +import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap import im.vector.matrix.android.internal.crypto.model.event.EncryptedEventContent +import im.vector.matrix.android.internal.crypto.model.rest.UserPasswordAuth +import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertNotNull import junit.framework.TestCase.assertTrue import junit.framework.TestCase.fail @@ -174,4 +184,104 @@ class KeyShareTests : InstrumentedTest { mTestHelper.signOutAndClose(aliceSession) mTestHelper.signOutAndClose(aliceSession2) } + + @Test + fun test_ShareSSSSSecret() { + + val aliceSession1 = mTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(true)) + + mTestHelper.doSync { + aliceSession1.cryptoService().crossSigningService() + .initializeCrossSigning(UserPasswordAuth( + user = aliceSession1.myUserId, + password = TestConstants.PASSWORD + ), it) + } + + val aliceSession2 = mTestHelper.logIntoAccount(aliceSession1.myUserId, SessionTestParams(true)) + + val aliceVerificationService1 = aliceSession1.cryptoService().verificationService() + val aliceVerificationService2 = aliceSession2.cryptoService().verificationService() + + //force keys download + mTestHelper.doSync> { + aliceSession1.cryptoService().downloadKeys(listOf(aliceSession1.myUserId), true, it) + } + mTestHelper.doSync> { + aliceSession2.cryptoService().downloadKeys(listOf(aliceSession2.myUserId), true, it) + } + + var session1ShortCode: String? = null + var session2ShortCode: String? = null + + aliceVerificationService1.addListener(object : VerificationService.Listener { + override fun transactionUpdated(tx: VerificationTransaction) { + Log.d("TEST", "AA: tx incoming?:${tx.isIncoming} state ${tx.state}") + if (tx is SasVerificationTransaction) { + if (tx.state == VerificationTxState.OnStarted) { + (tx as IncomingSasVerificationTransaction).performAccept() + } + if (tx.state == VerificationTxState.ShortCodeReady) { + session1ShortCode = tx.getDecimalCodeRepresentation() + tx.userHasVerifiedShortCode() + } + } + } + }) + + aliceVerificationService2.addListener(object : VerificationService.Listener { + override fun transactionUpdated(tx: VerificationTransaction) { + Log.d("TEST", "BB: tx incoming?:${tx.isIncoming} state ${tx.state}") + if (tx is SasVerificationTransaction) { + if (tx.state == VerificationTxState.ShortCodeReady) { + session2ShortCode = tx.getDecimalCodeRepresentation() + tx.userHasVerifiedShortCode() + } + } + } + }) + + val txId: String = "m.testVerif12" + aliceVerificationService2.beginKeyVerification(VerificationMethod.SAS, aliceSession1.myUserId, aliceSession1.sessionParams.credentials.deviceId + ?: "", txId) + + + waitWithLatch { latch -> + retryPeriodicallyWithLatch(latch) { + aliceSession1.cryptoService().getDeviceInfo(aliceSession1.myUserId, aliceSession2.sessionParams.credentials.deviceId ?: "")?.isVerified == true + } + } + + assertNotNull(session1ShortCode) + Log.d("TEST", "session1ShortCode: $session1ShortCode") + assertNotNull(session2ShortCode) + Log.d("TEST", "session2ShortCode: $session2ShortCode") + assertEquals(session1ShortCode, session2ShortCode) + + // SSK and USK private keys should have been shared + + waitWithLatch(300_000) { latch -> + retryPeriodicallyWithLatch(latch) { + aliceSession2.cryptoService().crossSigningService().canCrossSign() + } + } + } + + fun retryPeriodicallyWithLatch(latch: CountDownLatch, condition: (() -> Boolean)) { + GlobalScope.launch { + while (true) { + delay(1000) + if (condition()) { + latch.countDown() + return@launch + } + } + } + } + + fun waitWithLatch(timeout: Long? = null, block: (CountDownLatch) -> Unit) { + val latch = CountDownLatch(1) + block(latch) + mTestHelper.await(latch, timeout) + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt index 9e702ee9ac..83fb53424e 100755 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/DefaultCryptoService.kt @@ -140,7 +140,7 @@ internal class DefaultCryptoService @Inject constructor( private val crossSigningService: DefaultCrossSigningService, // - private val incomingRoomKeyRequestManager: IncomingRoomKeyRequestManager, + private val incomingGossipingRequestManager: IncomingGossipingRequestManager, // private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager, // Actions @@ -317,7 +317,7 @@ internal class DefaultCryptoService @Inject constructor( deviceListManager.invalidateAllDeviceLists() deviceListManager.refreshOutdatedDeviceLists() } else { - incomingRoomKeyRequestManager.processReceivedGossipingRequests() + incomingGossipingRequestManager.processReceivedGossipingRequests() } }.fold( { @@ -376,7 +376,7 @@ internal class DefaultCryptoService @Inject constructor( // Make sure we process to-device messages before generating new one-time-keys #2782 deviceListManager.refreshOutdatedDeviceLists() oneTimeKeysUploader.maybeUploadOneTimeKeys() - incomingRoomKeyRequestManager.processReceivedGossipingRequests() + incomingGossipingRequestManager.processReceivedGossipingRequests() } } } @@ -709,7 +709,7 @@ internal class DefaultCryptoService @Inject constructor( // save audit trail cryptoStore.saveGossipingEvent(event) // Requests are stacked, and will be handled one by one at the end of the sync (onSyncComplete) - incomingRoomKeyRequestManager.onGossipingRequestEvent(event) + incomingGossipingRequestManager.onGossipingRequestEvent(event) } EventType.SEND_SECRET -> { cryptoStore.saveGossipingEvent(event) @@ -1111,7 +1111,7 @@ internal class DefaultCryptoService @Inject constructor( * @param listener listener */ override fun addRoomKeysRequestListener(listener: GossipingRequestListener) { - incomingRoomKeyRequestManager.addRoomKeysRequestListener(listener) + incomingGossipingRequestManager.addRoomKeysRequestListener(listener) } /** @@ -1120,7 +1120,7 @@ internal class DefaultCryptoService @Inject constructor( * @param listener listener */ override fun removeRoomKeysRequestListener(listener: GossipingRequestListener) { - incomingRoomKeyRequestManager.removeRoomKeysRequestListener(listener) + incomingGossipingRequestManager.removeRoomKeysRequestListener(listener) } /** diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/GossipingRequestState.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/GossipingRequestState.kt index b218a2e387..16e8c35992 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/GossipingRequestState.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/GossipingRequestState.kt @@ -26,6 +26,7 @@ enum class GossipingRequestState { PENDING, REJECTED, ACCEPTED, + FAILED_TO_ACCEPTED, // USER_REJECTED, UNABLE_TO_PROCESS, CANCELLED_BY_REQUESTER, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingGossipingRequestManager.kt similarity index 91% rename from matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingGossipingRequestManager.kt index 0bb89154f1..8dfd264b11 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingRoomKeyRequestManager.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/IncomingGossipingRequestManager.kt @@ -32,7 +32,7 @@ import timber.log.Timber import javax.inject.Inject @SessionScope -internal class IncomingRoomKeyRequestManager @Inject constructor( +internal class IncomingGossipingRequestManager @Inject constructor( private val credentials: Credentials, private val cryptoStore: IMXCryptoStore, private val cryptoConfig: MXCryptoConfig, @@ -51,6 +51,32 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( receivedGossipingRequests.addAll(cryptoStore.getPendingIncomingGossipingRequests()) } + // Recently verified devices (map of deviceId and timestamp) + private val recentlyVerifiedDevices = HashMap() + + /** + * Called when a session has been verified. + * This information can be used by the manager to decide whether or not to fullfil gossiping requests + */ + fun onVerificationCompleteForDevice(deviceId: String) { + // For now we just keep an in memory cache + synchronized(recentlyVerifiedDevices) { + recentlyVerifiedDevices[deviceId] = System.currentTimeMillis() + } + } + + private fun hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId: String): Boolean { + val verifTimestamp: Long? + synchronized(recentlyVerifiedDevices) { + verifTimestamp = recentlyVerifiedDevices[deviceId] + } + if (verifTimestamp == null) return false + + val age = System.currentTimeMillis() - verifTimestamp + + return age < FIVE_MINUTES_IN_MILLIS + } + /** * Called when we get an m.room_key_request event * It must be called on CryptoThread @@ -257,9 +283,12 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( }?.let { secretValue -> // TODO check if locally trusted and not outdated Timber.i("## processIncomingSecretShareRequest() : Sharing secret $secretName with $device locally trusted") - if (isDeviceLocallyVerified == true) { + if (isDeviceLocallyVerified == true && hasBeenVerifiedLessThanFiveMinutesFromNow(deviceId)) { secretSecretCryptoProvider.shareSecretWithDevice(request, secretValue) cryptoStore.updateGossipingRequestState(request, GossipingRequestState.ACCEPTED) + } else { + Timber.v("## processIncomingSecretShareRequest() : Can't share secret $secretName with $device, verification too old") + cryptoStore.updateGossipingRequestState(request, GossipingRequestState.REJECTED) } return } @@ -340,4 +369,8 @@ internal class IncomingRoomKeyRequestManager @Inject constructor( gossipingRequestListeners.remove(listener) } } + + companion object { + private const val FIVE_MINUTES_IN_MILLIS = 5 * 60 * 1000 + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/SendGossipWorker.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/SendGossipWorker.kt new file mode 100644 index 0000000000..96791005d1 --- /dev/null +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/SendGossipWorker.kt @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2020 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 + +import android.content.Context +import androidx.work.CoroutineWorker +import androidx.work.Data +import androidx.work.WorkerParameters +import com.squareup.moshi.JsonClass +import im.vector.matrix.android.api.auth.data.Credentials +import im.vector.matrix.android.api.failure.shouldBeRetried +import im.vector.matrix.android.api.session.events.model.Event +import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.api.session.events.model.LocalEcho +import im.vector.matrix.android.api.session.events.model.toContent +import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter +import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap +import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent +import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore +import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask +import im.vector.matrix.android.internal.worker.WorkerParamsFactory +import im.vector.matrix.android.internal.worker.getSessionComponent +import org.greenrobot.eventbus.EventBus +import timber.log.Timber +import javax.inject.Inject + +internal class SendGossipWorker(context: Context, + params: WorkerParameters) + : CoroutineWorker(context, params) { + + @JsonClass(generateAdapter = true) + internal data class Params( + val sessionId: String, + val secretValue: String, + val request: IncomingSecretShareRequest + ) + + @Inject lateinit var sendToDeviceTask: SendToDeviceTask + @Inject lateinit var cryptoStore: IMXCryptoStore + @Inject lateinit var eventBus: EventBus + @Inject lateinit var credentials: Credentials +// @Inject lateinit var secretSecretCryptoProvider: ShareSecretCryptoProvider + @Inject lateinit var messageEncrypter: MessageEncrypter + + override suspend fun doWork(): Result { + val errorOutputData = Data.Builder().putBoolean("failed", true).build() + val params = WorkerParamsFactory.fromData(inputData) + ?: return Result.success(errorOutputData) + + val sessionComponent = getSessionComponent(params.sessionId) + ?: return Result.success(errorOutputData).also { + // TODO, can this happen? should I update local echo? + Timber.e("Unknown Session, cannot send message, sessionId: ${params.sessionId}") + } + sessionComponent.inject(this) + + val localId = LocalEcho.createLocalEchoId() + val eventType: String = EventType.SEND_SECRET + + val toDeviceContent = SecretSendEventContent( + requestId = params.request.requestId ?: "", + secretValue = params.secretValue + ) + + val requestingUserId = params.request.userId ?: "" + val requestingDeviceId = params.request.deviceId ?: "" + val deviceInfo = cryptoStore.getUserDevice(requestingUserId, requestingDeviceId) + ?: return Result.success(errorOutputData).also { + cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.FAILED_TO_ACCEPTED) + Timber.e("Unknown deviceInfo, cannot send message, sessionId: ${params.request.deviceId}") + } + + val payloadJson = mutableMapOf("type" to EventType.SEND_SECRET) + payloadJson["content"] = toDeviceContent.toContent() + + val sendToDeviceMap = MXUsersDevicesMap() + + try { + val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo)) + sendToDeviceMap.setObject(requestingUserId, requestingDeviceId, encodedPayload) + } catch (failure: Throwable) { + Timber.e("## Fail to encrypt gossip + ${failure.localizedMessage}") + } + + + cryptoStore.saveGossipingEvent(Event( + type = eventType, + content = toDeviceContent.toContent(), + senderId = credentials.userId + ).also { + it.ageLocalTs = System.currentTimeMillis() + }) + + try { + sendToDeviceTask.execute( + SendToDeviceTask.Params( + eventType = eventType, + contentMap = sendToDeviceMap, + transactionId = localId + ) + ) + cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.ACCEPTED) + return Result.success() + } catch (exception: Throwable) { + return if (exception.shouldBeRetried()) { + Result.retry() + } else { + cryptoStore.updateGossipingRequestState(params.request, GossipingRequestState.FAILED_TO_ACCEPTED) + Result.success(errorOutputData) + } + } + } +} diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ShareSecretCryptoProvider.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ShareSecretCryptoProvider.kt index 78e587c0f1..7a7f6acb5f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ShareSecretCryptoProvider.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/ShareSecretCryptoProvider.kt @@ -18,16 +18,17 @@ package im.vector.matrix.android.internal.crypto import im.vector.matrix.android.api.session.events.model.Event import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.api.session.events.model.toContent import im.vector.matrix.android.internal.crypto.actions.MessageEncrypter import im.vector.matrix.android.internal.crypto.algorithms.olm.MXOlmDecryptionFactory import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap import im.vector.matrix.android.internal.crypto.model.event.SecretSendEventContent import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore import im.vector.matrix.android.internal.crypto.tasks.SendToDeviceTask +import im.vector.matrix.android.internal.di.UserId import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking import timber.log.Timber import javax.inject.Inject @@ -35,6 +36,7 @@ internal class ShareSecretCryptoProvider @Inject constructor( val messageEncrypter: MessageEncrypter, val sendToDeviceTask: SendToDeviceTask, val deviceListManager: DeviceListManager, + @UserId val myUserId: String, private val olmDecryptionFactory: MXOlmDecryptionFactory, val cryptoCoroutineScope: CoroutineScope, val cryptoStore: IMXCryptoStore, @@ -43,32 +45,38 @@ internal class ShareSecretCryptoProvider @Inject constructor( fun shareSecretWithDevice(request: IncomingSecretShareRequest, secretValue: String) { val userId = request.userId ?: return cryptoCoroutineScope.launch(coroutineDispatchers.crypto) { - runCatching { deviceListManager.downloadKeys(listOf(userId), false) } - .mapCatching { - val deviceId = request.deviceId - val deviceInfo = cryptoStore.getUserDevice(userId, deviceId ?: "") ?: throw RuntimeException() + // runCatching { deviceListManager.downloadKeys(listOf(userId), false) } +// .mapCatching { + val deviceId = request.deviceId + val deviceInfo = cryptoStore.getUserDevice(userId, deviceId ?: "") ?: return@launch - Timber.i("## shareSecretWithDevice() : sharing secret ${request.secretName} with device $userId:$deviceId") - val payloadJson = mutableMapOf("type" to EventType.SEND_SECRET) - payloadJson["content"] = SecretSendEventContent( - requestId = request.requestId ?: "", - secretValue = secretValue - ) + Timber.i("## shareSecretWithDevice() : sharing secret ${request.secretName} with device $userId:$deviceId") - val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo)) - val sendToDeviceMap = MXUsersDevicesMap() - sendToDeviceMap.setObject(userId, deviceId, encodedPayload) - Timber.i("## shareSecretWithDevice() : sending to $userId:$deviceId") - val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap) - sendToDeviceTask.execute(sendToDeviceParams) - } + val payloadJson = mutableMapOf("type" to EventType.SEND_SECRET) + val secretContent = SecretSendEventContent( + requestId = request.requestId ?: "", + secretValue = secretValue + ) + payloadJson["content"] = secretContent.toContent() + + cryptoStore.saveGossipingEvent(Event( + type = EventType.SEND_SECRET, + content = secretContent.toContent(), + senderId = myUserId + )) + + val encodedPayload = messageEncrypter.encryptMessage(payloadJson, listOf(deviceInfo)) + val sendToDeviceMap = MXUsersDevicesMap() + sendToDeviceMap.setObject(userId, deviceId, encodedPayload) + Timber.i("## shareSecretWithDevice() : sending to $userId:$deviceId") + val sendToDeviceParams = SendToDeviceTask.Params(EventType.ENCRYPTED, sendToDeviceMap) + sendToDeviceTask.execute(sendToDeviceParams) +// } } } fun decryptEvent(event: Event): MXEventDecryptionResult { - return runBlocking(coroutineDispatchers.crypto) { - olmDecryptionFactory.create().decryptEvent(event, ShareSecretCryptoProvider::class.java.name ?: "") - } + return olmDecryptionFactory.create().decryptEvent(event, ShareSecretCryptoProvider::class.java.name ?: "") } } 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 74a4c6bee8..45af09f05b 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 @@ -25,7 +25,6 @@ import im.vector.matrix.android.api.util.Optional import im.vector.matrix.android.internal.crypto.DeviceListManager import im.vector.matrix.android.internal.crypto.MXOlmDevice import im.vector.matrix.android.internal.crypto.MyDeviceInfoHolder -import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager import im.vector.matrix.android.internal.crypto.model.CryptoCrossSigningKey import im.vector.matrix.android.internal.crypto.model.KeyUsage import im.vector.matrix.android.internal.crypto.model.rest.UploadSignatureQueryBuilder @@ -62,7 +61,6 @@ internal class DefaultCrossSigningService @Inject constructor( private val taskExecutor: TaskExecutor, private val coroutineDispatchers: MatrixCoroutineDispatchers, private val cryptoCoroutineScope: CoroutineScope, - private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager, private val eventBus: EventBus) : CrossSigningService, DeviceListManager.UserDevicesUpdateListener { private var olmUtility: OlmUtility? = null @@ -598,7 +596,7 @@ internal class DefaultCrossSigningService @Inject constructor( } override fun canCrossSign(): Boolean { - return checkSelfTrust().isVerified() && cryptoStore.getCrossSigningPrivateKeys()?.selfSigned != null + return cryptoStore.getCrossSigningPrivateKeys()?.selfSigned != null } override fun trustUser(otherUserId: String, callback: MatrixCallback) { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt index 989ddc9804..e3a765f95c 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultIncomingSASDefaultVerificationTransaction.kt @@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.crypto.verification.IncomingSasVerif import im.vector.matrix.android.api.session.crypto.verification.SasMode import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore @@ -35,6 +36,7 @@ internal class DefaultIncomingSASDefaultVerificationTransaction( private val cryptoStore: IMXCryptoStore, crossSigningService: CrossSigningService, outgoingGossipingRequestManager: OutgoingGossipingRequestManager, + incomingGossipingRequestManager: IncomingGossipingRequestManager, deviceFingerprint: String, transactionId: String, otherUserID: String, @@ -46,6 +48,7 @@ internal class DefaultIncomingSASDefaultVerificationTransaction( cryptoStore, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, deviceFingerprint, transactionId, otherUserID, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt index 6c7e8f29d3..7fd97d0231 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultOutgoingSASDefaultVerificationTransaction.kt @@ -20,6 +20,7 @@ import im.vector.matrix.android.api.session.crypto.verification.CancelCode import im.vector.matrix.android.api.session.crypto.verification.OutgoingSasVerificationTransaction import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore @@ -32,6 +33,7 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction( cryptoStore: IMXCryptoStore, crossSigningService: CrossSigningService, outgoingGossipingRequestManager: OutgoingGossipingRequestManager, + incomingGossipingRequestManager: IncomingGossipingRequestManager, deviceFingerprint: String, transactionId: String, otherUserId: String, @@ -43,6 +45,7 @@ internal class DefaultOutgoingSASDefaultVerificationTransaction( cryptoStore, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, deviceFingerprint, transactionId, otherUserId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt index 400b2c520e..a0420b0125 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationService.kt @@ -50,6 +50,7 @@ import im.vector.matrix.android.api.session.room.model.message.MessageVerificati import im.vector.matrix.android.api.session.room.model.message.MessageVerificationStartContent import im.vector.matrix.android.api.session.room.model.message.ValidVerificationDone import im.vector.matrix.android.internal.crypto.DeviceListManager +import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager import im.vector.matrix.android.internal.crypto.MyDeviceInfoHolder import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction @@ -90,6 +91,7 @@ internal class DefaultVerificationService @Inject constructor( @DeviceId private val deviceId: String?, private val cryptoStore: IMXCryptoStore, private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager, + private val incomingGossipingRequestManager: IncomingGossipingRequestManager, private val myDeviceInfoHolder: Lazy, private val deviceListManager: DeviceListManager, private val setDeviceVerificationAction: SetDeviceVerificationAction, @@ -530,6 +532,7 @@ internal class DefaultVerificationService @Inject constructor( cryptoStore, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, myDeviceInfoHolder.get().myDevice.fingerprint()!!, startReq.transactionId, otherUserId, @@ -840,6 +843,7 @@ internal class DefaultVerificationService @Inject constructor( readyReq.fromDevice, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, cryptoStore, qrCodeData, userId, @@ -1022,6 +1026,7 @@ internal class DefaultVerificationService @Inject constructor( cryptoStore, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, myDeviceInfoHolder.get().myDevice.fingerprint()!!, txID, otherUserId, @@ -1198,6 +1203,7 @@ internal class DefaultVerificationService @Inject constructor( cryptoStore, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, myDeviceInfoHolder.get().myDevice.fingerprint()!!, transactionId, otherUserId, @@ -1335,6 +1341,7 @@ internal class DefaultVerificationService @Inject constructor( otherDeviceId, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, cryptoStore, qrCodeData, userId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt index cb83fdfe8b..973b9944cb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/DefaultVerificationTransaction.kt @@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.verification.VerificationTransaction import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState +import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction import im.vector.matrix.android.internal.crypto.crosssigning.DeviceTrustLevel @@ -33,6 +34,7 @@ internal abstract class DefaultVerificationTransaction( private val setDeviceVerificationAction: SetDeviceVerificationAction, private val crossSigningService: CrossSigningService, private val outgoingGossipingRequestManager: OutgoingGossipingRequestManager, + private val incomingGossipingRequestManager: IncomingGossipingRequestManager, private val userId: String, override val transactionId: String, override val otherUserId: String, @@ -86,6 +88,8 @@ internal abstract class DefaultVerificationTransaction( } if (otherUserId == userId) { + incomingGossipingRequestManager.onVerificationCompleteForDevice(otherDeviceId!!) + // If me it's reasonable to sign and upload the device signature // Notice that i might not have the private keys, so may not be able to do it crossSigningService.trustDevice(otherDeviceId!!, object : MatrixCallback { @@ -96,7 +100,7 @@ internal abstract class DefaultVerificationTransaction( } transport.done(transactionId) { - if (otherUserId == userId) { + if (otherUserId == userId && !crossSigningService.canCrossSign()) { outgoingGossipingRequestManager.sendSecretShareRequest(SELF_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))) outgoingGossipingRequestManager.sendSecretShareRequest(USER_SIGNING_KEY_SSSS_NAME, mapOf(userId to listOf(otherDeviceId ?: "*"))) } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASDefaultVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASDefaultVerificationTransaction.kt index cfb3d7e38e..a878ad06eb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASDefaultVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/SASDefaultVerificationTransaction.kt @@ -24,6 +24,7 @@ import im.vector.matrix.android.api.session.crypto.verification.SasMode import im.vector.matrix.android.api.session.crypto.verification.SasVerificationTransaction import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction import im.vector.matrix.android.internal.crypto.model.MXKey @@ -44,6 +45,7 @@ internal abstract class SASDefaultVerificationTransaction( private val cryptoStore: IMXCryptoStore, crossSigningService: CrossSigningService, outgoingGossipingRequestManager: OutgoingGossipingRequestManager, + incomingGossipingRequestManager: IncomingGossipingRequestManager, private val deviceFingerprint: String, transactionId: String, otherUserId: String, @@ -53,6 +55,7 @@ internal abstract class SASDefaultVerificationTransaction( setDeviceVerificationAction, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, userId, transactionId, otherUserId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt index 8fc12f000a..41d8ce7f44 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/crypto/verification/qrcode/DefaultQrCodeVerificationTransaction.kt @@ -21,6 +21,7 @@ import im.vector.matrix.android.api.session.crypto.verification.CancelCode import im.vector.matrix.android.api.session.crypto.verification.QrCodeVerificationTransaction import im.vector.matrix.android.api.session.crypto.verification.VerificationTxState import im.vector.matrix.android.api.session.events.model.EventType +import im.vector.matrix.android.internal.crypto.IncomingGossipingRequestManager import im.vector.matrix.android.internal.crypto.OutgoingGossipingRequestManager import im.vector.matrix.android.internal.crypto.actions.SetDeviceVerificationAction import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64 @@ -38,6 +39,7 @@ internal class DefaultQrCodeVerificationTransaction( override var otherDeviceId: String?, private val crossSigningService: CrossSigningService, outgoingGossipingRequestManager: OutgoingGossipingRequestManager, + incomingGossipingRequestManager: IncomingGossipingRequestManager, private val cryptoStore: IMXCryptoStore, // Not null only if other user is able to scan QR code private val qrCodeData: QrCodeData?, @@ -48,6 +50,7 @@ internal class DefaultQrCodeVerificationTransaction( setDeviceVerificationAction, crossSigningService, outgoingGossipingRequestManager, + incomingGossipingRequestManager, userId, transactionId, otherUserId, diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt index 2185d3b278..22ebb4273a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionComponent.kt @@ -23,6 +23,7 @@ import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.internal.crypto.CancelGossipRequestWorker import im.vector.matrix.android.internal.crypto.CryptoModule import im.vector.matrix.android.internal.crypto.SendGossipRequestWorker +import im.vector.matrix.android.internal.crypto.SendGossipWorker import im.vector.matrix.android.internal.crypto.verification.SendVerificationMessageWorker import im.vector.matrix.android.internal.di.MatrixComponent import im.vector.matrix.android.internal.di.SessionAssistedInjectModule @@ -109,8 +110,11 @@ internal interface SessionComponent { fun inject(worker: SendVerificationMessageWorker) fun inject(worker: SendGossipRequestWorker) + fun inject(worker: CancelGossipRequestWorker) + fun inject(worker: SendGossipWorker) + @Component.Factory interface Factory { fun create( diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt index 02c06b0e56..ebffef33f3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/timeline/TimelineEventDecryptor.kt @@ -128,7 +128,7 @@ internal class TimelineEventDecryptor @Inject constructor( } } } catch (t: Throwable) { - Timber.e(t, "Failed to decrypt event $eventId") + Timber.e( "Failed to decrypt event $eventId, ${t.localizedMessage}") } finally { synchronized(existingRequests) { existingRequests.remove(request)