mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-16 20:10:04 +03:00
Missing backup signature
Ensure device keys before bootstrap cross signing
This commit is contained in:
parent
fbb645d9d4
commit
85b9dda092
4 changed files with 90 additions and 23 deletions
|
@ -26,6 +26,7 @@ import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.assertFalse
|
import org.junit.Assert.assertFalse
|
||||||
import org.junit.Assert.assertNotNull
|
import org.junit.Assert.assertNotNull
|
||||||
import org.junit.Assert.assertTrue
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Assume
|
||||||
import org.junit.FixMethodOrder
|
import org.junit.FixMethodOrder
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
@ -128,6 +129,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||||
@Test
|
@Test
|
||||||
fun createKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
|
fun createKeysBackupVersionTest() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
|
||||||
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
|
val bobSession = testHelper.createAccount(TestConstants.USER_BOB, KeysBackupTestConstants.defaultSessionParams)
|
||||||
|
Log.d("#E2E", "Initializing crosssigning for ${bobSession.myUserId.take(8)}")
|
||||||
cryptoTestHelper.initializeCrossSigning(bobSession)
|
cryptoTestHelper.initializeCrossSigning(bobSession)
|
||||||
|
|
||||||
val keysBackup = bobSession.cryptoService().keysBackupService()
|
val keysBackup = bobSession.cryptoService().keysBackupService()
|
||||||
|
@ -136,12 +138,14 @@ class KeysBackupTest : InstrumentedTest {
|
||||||
|
|
||||||
assertFalse(keysBackup.isEnabled())
|
assertFalse(keysBackup.isEnabled())
|
||||||
|
|
||||||
|
Log.d("#E2E", "prepareKeysBackupVersion")
|
||||||
val megolmBackupCreationInfo =
|
val megolmBackupCreationInfo =
|
||||||
keysBackup.prepareKeysBackupVersion(null, null)
|
keysBackup.prepareKeysBackupVersion(null, null)
|
||||||
|
|
||||||
assertFalse(keysBackup.isEnabled())
|
assertFalse(keysBackup.isEnabled())
|
||||||
|
|
||||||
// Create the version
|
// Create the version
|
||||||
|
Log.d("#E2E", "createKeysBackupVersion")
|
||||||
val version = keysBackup.createKeysBackupVersion(megolmBackupCreationInfo)
|
val version = keysBackup.createKeysBackupVersion(megolmBackupCreationInfo)
|
||||||
|
|
||||||
// Backup must be enable now
|
// Backup must be enable now
|
||||||
|
@ -151,6 +155,7 @@ class KeysBackupTest : InstrumentedTest {
|
||||||
val versionResult = keysBackup.getVersion(version.version)
|
val versionResult = keysBackup.getVersion(version.version)
|
||||||
val trust = keysBackup.getKeysBackupTrust(versionResult!!)
|
val trust = keysBackup.getKeysBackupTrust(versionResult!!)
|
||||||
|
|
||||||
|
Log.d("#E2E", "Check backup signatures")
|
||||||
assertEquals("Should have 2 signatures", 2, trust.signatures.size)
|
assertEquals("Should have 2 signatures", 2, trust.signatures.size)
|
||||||
|
|
||||||
trust.signatures
|
trust.signatures
|
||||||
|
@ -672,11 +677,16 @@ class KeysBackupTest : InstrumentedTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun testBackupWithPassword() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
|
fun testBackupWithPassword() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
|
||||||
|
|
||||||
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
|
val keysBackupTestHelper = KeysBackupTestHelper(testHelper, cryptoTestHelper)
|
||||||
|
|
||||||
val password = "password"
|
val password = "password"
|
||||||
|
|
||||||
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
val testData = keysBackupTestHelper.createKeysBackupScenarioWithPassword(password)
|
||||||
|
Assume.assumeTrue(
|
||||||
|
"Can't report progress same way in rust",
|
||||||
|
testData.cryptoTestData.firstSession.cryptoService().name() != "rust-sdk"
|
||||||
|
)
|
||||||
|
|
||||||
// - Restore the e2e backup with the password
|
// - Restore the e2e backup with the password
|
||||||
val steps = ArrayList<StepProgressListener.Step>()
|
val steps = ArrayList<StepProgressListener.Step>()
|
||||||
|
|
|
@ -82,6 +82,7 @@ import org.matrix.rustcomponents.sdk.crypto.RequestType
|
||||||
import org.matrix.rustcomponents.sdk.crypto.RoomKeyCounts
|
import org.matrix.rustcomponents.sdk.crypto.RoomKeyCounts
|
||||||
import org.matrix.rustcomponents.sdk.crypto.ShieldColor
|
import org.matrix.rustcomponents.sdk.crypto.ShieldColor
|
||||||
import org.matrix.rustcomponents.sdk.crypto.ShieldState
|
import org.matrix.rustcomponents.sdk.crypto.ShieldState
|
||||||
|
import org.matrix.rustcomponents.sdk.crypto.SignatureVerification
|
||||||
import org.matrix.rustcomponents.sdk.crypto.setLogger
|
import org.matrix.rustcomponents.sdk.crypto.setLogger
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
@ -916,7 +917,7 @@ internal class OlmMachine @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(CryptoStoreException::class)
|
@Throws(CryptoStoreException::class)
|
||||||
suspend fun checkAuthDataSignature(authData: KeysAlgorithmAndData): Boolean {
|
suspend fun checkAuthDataSignature(authData: KeysAlgorithmAndData): SignatureVerification {
|
||||||
return withContext(coroutineDispatchers.computation) {
|
return withContext(coroutineDispatchers.computation) {
|
||||||
val adapter = moshi
|
val adapter = moshi
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
|
@ -929,7 +930,7 @@ internal class OlmMachine @Inject constructor(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
inner.verifyBackup(serializedAuthData).trusted
|
inner.verifyBackup(serializedAuthData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,10 +28,13 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo
|
||||||
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel
|
||||||
import org.matrix.android.sdk.api.util.Optional
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
import org.matrix.android.sdk.internal.crypto.network.OutgoingRequestsProcessor
|
||||||
|
import org.matrix.rustcomponents.sdk.crypto.Request
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal class RustCrossSigningService @Inject constructor(
|
internal class RustCrossSigningService @Inject constructor(
|
||||||
private val olmMachine: OlmMachine,
|
private val olmMachine: OlmMachine,
|
||||||
|
private val outgoingRequestsProcessor: OutgoingRequestsProcessor,
|
||||||
private val computeShieldForGroup: ComputeShieldForGroupUseCase
|
private val computeShieldForGroup: ComputeShieldForGroupUseCase
|
||||||
) : CrossSigningService {
|
) : CrossSigningService {
|
||||||
|
|
||||||
|
@ -78,6 +81,10 @@ internal class RustCrossSigningService @Inject constructor(
|
||||||
* Users needs to enter credentials
|
* Users needs to enter credentials
|
||||||
*/
|
*/
|
||||||
override suspend fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?) {
|
override suspend fun initializeCrossSigning(uiaInterceptor: UserInteractiveAuthInterceptor?) {
|
||||||
|
// ensure our keys are sent before initialising
|
||||||
|
outgoingRequestsProcessor.processOutgoingRequests(olmMachine) {
|
||||||
|
it is Request.KeysUpload
|
||||||
|
}
|
||||||
olmMachine.bootstrapCrossSigning(uiaInterceptor)
|
olmMachine.bootstrapCrossSigning(uiaInterceptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrust
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrust
|
||||||
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupVersionTrustSignature
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupAuthData
|
||||||
|
@ -67,6 +68,8 @@ import org.matrix.android.sdk.internal.util.JsonCanonicalizer
|
||||||
import org.matrix.olm.OlmException
|
import org.matrix.olm.OlmException
|
||||||
import org.matrix.rustcomponents.sdk.crypto.Request
|
import org.matrix.rustcomponents.sdk.crypto.Request
|
||||||
import org.matrix.rustcomponents.sdk.crypto.RequestType
|
import org.matrix.rustcomponents.sdk.crypto.RequestType
|
||||||
|
import org.matrix.rustcomponents.sdk.crypto.SignatureState
|
||||||
|
import org.matrix.rustcomponents.sdk.crypto.SignatureVerification
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.security.InvalidParameterException
|
import java.security.InvalidParameterException
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -266,14 +269,56 @@ internal class RustKeyBackupService @Inject constructor(
|
||||||
private suspend fun checkBackupTrust(algAndData: KeysAlgorithmAndData?): KeysBackupVersionTrust {
|
private suspend fun checkBackupTrust(algAndData: KeysAlgorithmAndData?): KeysBackupVersionTrust {
|
||||||
if (algAndData == null) return KeysBackupVersionTrust(usable = false)
|
if (algAndData == null) return KeysBackupVersionTrust(usable = false)
|
||||||
try {
|
try {
|
||||||
val isTrusted = olmMachine.checkAuthDataSignature(algAndData)
|
val authData = olmMachine.checkAuthDataSignature(algAndData)
|
||||||
return KeysBackupVersionTrust(isTrusted)
|
val signatures = authData.mapRustToAPI()
|
||||||
|
return KeysBackupVersionTrust(authData.trusted, signatures)
|
||||||
} catch (failure: Throwable) {
|
} catch (failure: Throwable) {
|
||||||
Timber.w(failure, "Failed to trust backup")
|
Timber.w(failure, "Failed to trust backup")
|
||||||
return KeysBackupVersionTrust(usable = false)
|
return KeysBackupVersionTrust(usable = false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun SignatureVerification.mapRustToAPI(): List<KeysBackupVersionTrustSignature> {
|
||||||
|
val signatures = mutableListOf<KeysBackupVersionTrustSignature>()
|
||||||
|
// signature state of own device
|
||||||
|
val ownDeviceState = this.deviceSignature
|
||||||
|
if (ownDeviceState != SignatureState.MISSING && ownDeviceState != SignatureState.INVALID) {
|
||||||
|
// we can add it
|
||||||
|
signatures.add(
|
||||||
|
KeysBackupVersionTrustSignature.DeviceSignature(
|
||||||
|
olmMachine.deviceId(),
|
||||||
|
olmMachine.getCryptoDeviceInfo(olmMachine.userId(), olmMachine.deviceId()),
|
||||||
|
ownDeviceState == SignatureState.VALID_AND_TRUSTED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// signature state of our own identity
|
||||||
|
val ownIdentityState = this.userIdentitySignature
|
||||||
|
if (ownIdentityState != SignatureState.MISSING && ownIdentityState != SignatureState.INVALID) {
|
||||||
|
// we can add it
|
||||||
|
val masterKey = olmMachine.getIdentity(olmMachine.userId())?.toMxCrossSigningInfo()?.masterKey()
|
||||||
|
signatures.add(
|
||||||
|
KeysBackupVersionTrustSignature.UserSignature(
|
||||||
|
masterKey?.unpaddedBase64PublicKey,
|
||||||
|
masterKey,
|
||||||
|
ownIdentityState == SignatureState.VALID_AND_TRUSTED
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
signatures.addAll(
|
||||||
|
this.otherDevicesSignatures
|
||||||
|
.filter { it.value == SignatureState.VALID_AND_TRUSTED || it.value == SignatureState.VALID_BUT_NOT_TRUSTED }
|
||||||
|
.map {
|
||||||
|
KeysBackupVersionTrustSignature.DeviceSignature(
|
||||||
|
it.key,
|
||||||
|
olmMachine.getCryptoDeviceInfo(olmMachine.userId(), it.key),
|
||||||
|
ownDeviceState == SignatureState.VALID_AND_TRUSTED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return signatures
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult): KeysBackupVersionTrust {
|
override suspend fun getKeysBackupTrust(keysBackupVersion: KeysVersionResult): KeysBackupVersionTrust {
|
||||||
return withContext(coroutineDispatchers.crypto) {
|
return withContext(coroutineDispatchers.crypto) {
|
||||||
checkBackupTrust(keysBackupVersion)
|
checkBackupTrust(keysBackupVersion)
|
||||||
|
@ -570,20 +615,24 @@ internal class RustKeyBackupService @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun restoreKeysWithRecoveryKey(keysVersionResult: KeysVersionResult,
|
override suspend fun restoreKeysWithRecoveryKey(
|
||||||
|
keysVersionResult: KeysVersionResult,
|
||||||
recoveryKey: IBackupRecoveryKey,
|
recoveryKey: IBackupRecoveryKey,
|
||||||
roomId: String?,
|
roomId: String?,
|
||||||
sessionId: String?,
|
sessionId: String?,
|
||||||
stepProgressListener: StepProgressListener?): ImportRoomKeysResult {
|
stepProgressListener: StepProgressListener?
|
||||||
|
): ImportRoomKeysResult {
|
||||||
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
|
Timber.v("restoreKeysWithRecoveryKey: From backup version: ${keysVersionResult.version}")
|
||||||
return restoreBackup(keysVersionResult, recoveryKey, roomId, sessionId, stepProgressListener)
|
return restoreBackup(keysVersionResult, recoveryKey, roomId, sessionId, stepProgressListener)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun restoreKeyBackupWithPassword(keysBackupVersion: KeysVersionResult,
|
override suspend fun restoreKeyBackupWithPassword(
|
||||||
|
keysBackupVersion: KeysVersionResult,
|
||||||
password: String,
|
password: String,
|
||||||
roomId: String?,
|
roomId: String?,
|
||||||
sessionId: String?,
|
sessionId: String?,
|
||||||
stepProgressListener: StepProgressListener?): ImportRoomKeysResult {
|
stepProgressListener: StepProgressListener?
|
||||||
|
): ImportRoomKeysResult {
|
||||||
Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
|
Timber.v("[MXKeyBackup] restoreKeyBackup with password: From backup version: ${keysBackupVersion.version}")
|
||||||
val recoveryKey = withContext(coroutineDispatchers.crypto) {
|
val recoveryKey = withContext(coroutineDispatchers.crypto) {
|
||||||
recoveryKeyFromPassword(password, keysBackupVersion)
|
recoveryKeyFromPassword(password, keysBackupVersion)
|
||||||
|
|
Loading…
Add table
Reference in a new issue