Skip to content

Commit 214867a

Browse files
authored
Merge pull request #7248 from vector-im/feature/bca/hotfix_1.5.1_merge
Feature/bca/hotfix 1.5.1 merge back from main
2 parents 75a381e + 803eff9 commit 214867a

File tree

46 files changed

+1025
-252
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+1025
-252
lines changed

CHANGES.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
Changes in Element v1.5.1 (2022-09-28)
2+
======================================
3+
4+
Security ⚠️
5+
----------
6+
7+
This update provides important security fixes, update now.
8+
Ref: CVE-2022-39246 CVE-2022-39248
9+
110
Changes in Element v1.5.0 (2022-09-23)
211
======================================
312

library/ui-strings/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2617,6 +2617,7 @@
26172617

26182618
<string name="unencrypted">Unencrypted</string>
26192619
<string name="encrypted_unverified">Encrypted by an unverified device</string>
2620+
<string name="key_authenticity_not_guaranteed">The authenticity of this encrypted message can\'t be guaranteed on this device.</string>
26202621
<string name="review_logins">Review where you’re logged in</string>
26212622
<string name="verify_other_sessions">Verify all your sessions to ensure your account &amp; messages are safe</string>
26222623
<!-- Argument will be replaced by the other session name (e.g, Desktop, mobile) -->

library/ui-styles/src/main/res/values/colors.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@
143143
<color name="shield_color_trust">#0DBD8B</color>
144144
<color name="shield_color_trust_background">#0F0DBD8B</color>
145145
<color name="shield_color_black">#17191C</color>
146+
<color name="shield_color_gray">#91A1C0</color>
146147
<color name="shield_color_warning">#FF4B55</color>
147148
<color name="shield_color_warning_background">#0FFF4B55</color>
148149

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/account/DeactivateAccountTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import kotlin.coroutines.resume
4040
class DeactivateAccountTest : InstrumentedTest {
4141

4242
@Test
43-
fun deactivateAccountTest() = runSessionTest(context(), false /* session will be deactivated */) { commonTestHelper ->
43+
fun deactivateAccountTest() = runSessionTest(context(), autoSignoutOnClose = false /* session will be deactivated */) { commonTestHelper ->
4444
val session = commonTestHelper.createAccount(TestConstants.USER_ALICE, SessionTestParams(withInitialSync = true))
4545

4646
// Deactivate the account

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import org.matrix.android.sdk.api.MatrixConfiguration
3737
import org.matrix.android.sdk.api.SyncConfig
3838
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
3939
import org.matrix.android.sdk.api.auth.registration.RegistrationResult
40+
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
4041
import org.matrix.android.sdk.api.session.Session
4142
import org.matrix.android.sdk.api.session.events.model.EventType
4243
import org.matrix.android.sdk.api.session.events.model.toModel
@@ -60,13 +61,13 @@ import kotlin.coroutines.suspendCoroutine
6061
* This class exposes methods to be used in common cases
6162
* Registration, login, Sync, Sending messages...
6263
*/
63-
class CommonTestHelper internal constructor(context: Context) {
64+
class CommonTestHelper internal constructor(context: Context, val cryptoConfig: MXCryptoConfig? = null) {
6465

6566
companion object {
6667

6768
@OptIn(ExperimentalCoroutinesApi::class)
68-
internal fun runSessionTest(context: Context, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CommonTestHelper) -> Unit) {
69-
val testHelper = CommonTestHelper(context)
69+
internal fun runSessionTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CommonTestHelper) -> Unit) {
70+
val testHelper = CommonTestHelper(context, cryptoConfig)
7071
return runTest(dispatchTimeoutMs = TestConstants.timeOutMillis) {
7172
try {
7273
withContext(Dispatchers.Default) {
@@ -81,8 +82,8 @@ class CommonTestHelper internal constructor(context: Context) {
8182
}
8283

8384
@OptIn(ExperimentalCoroutinesApi::class)
84-
internal fun runCryptoTest(context: Context, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CryptoTestHelper, CommonTestHelper) -> Unit) {
85-
val testHelper = CommonTestHelper(context)
85+
internal fun runCryptoTest(context: Context, cryptoConfig: MXCryptoConfig? = null, autoSignoutOnClose: Boolean = true, block: suspend CoroutineScope.(CryptoTestHelper, CommonTestHelper) -> Unit) {
86+
val testHelper = CommonTestHelper(context, cryptoConfig)
8687
val cryptoTestHelper = CryptoTestHelper(testHelper)
8788
return runTest(dispatchTimeoutMs = TestConstants.timeOutMillis) {
8889
try {
@@ -114,6 +115,7 @@ class CommonTestHelper internal constructor(context: Context) {
114115
applicationFlavor = "TestFlavor",
115116
roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider(),
116117
syncConfig = SyncConfig(longPollTimeout = 5_000L),
118+
cryptoConfig = cryptoConfig ?: MXCryptoConfig()
117119
)
118120
)
119121
}

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CryptoTestHelper.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -394,14 +394,16 @@ class CryptoTestHelper(val testHelper: CommonTestHelper) {
394394
suspend fun ensureCanDecrypt(sentEventIds: List<String>, session: Session, e2eRoomID: String, messagesText: List<String>) {
395395
sentEventIds.forEachIndexed { index, sentEventId ->
396396
testHelper.retryPeriodically {
397-
val event = session.getRoom(e2eRoomID)!!.timelineService().getTimelineEvent(sentEventId)!!.root
397+
val event = session.getRoom(e2eRoomID)?.timelineService()?.getTimelineEvent(sentEventId)?.root
398+
?: return@retryPeriodically false
398399
try {
399400
session.cryptoService().decryptEvent(event, "").let { result ->
400401
event.mxDecryptionResult = OlmDecryptionResult(
401402
payload = result.clearEvent,
402403
senderKey = result.senderCurve25519Key,
403404
keysClaimed = result.claimedEd25519Key?.let { mapOf("ed25519" to it) },
404-
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain
405+
forwardingCurve25519KeyChain = result.forwardingCurve25519KeyChain,
406+
isSafe = result.isSafe
405407
)
406408
}
407409
} catch (error: MXCryptoError) {

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeSanityTests.kt

Lines changed: 34 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ import org.junit.runner.RunWith
3333
import org.junit.runners.JUnit4
3434
import org.junit.runners.MethodSorters
3535
import org.matrix.android.sdk.InstrumentedTest
36+
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
3637
import org.matrix.android.sdk.api.session.Session
3738
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
38-
import org.matrix.android.sdk.api.session.crypto.RequestResult
3939
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersion
4040
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysVersionResult
4141
import org.matrix.android.sdk.api.session.crypto.keysbackup.MegolmBackupCreationInfo
@@ -49,7 +49,6 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationServic
4949
import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransaction
5050
import org.matrix.android.sdk.api.session.events.model.EventType
5151
import org.matrix.android.sdk.api.session.events.model.content.EncryptedEventContent
52-
import org.matrix.android.sdk.api.session.events.model.content.WithHeldCode
5352
import org.matrix.android.sdk.api.session.events.model.toModel
5453
import org.matrix.android.sdk.api.session.getRoom
5554
import org.matrix.android.sdk.api.session.room.Room
@@ -130,7 +129,8 @@ class E2eeSanityTests : InstrumentedTest {
130129
val timeLineEvent = otherSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId!!)
131130
timeLineEvent != null &&
132131
timeLineEvent.isEncrypted() &&
133-
timeLineEvent.root.getClearType() == EventType.MESSAGE
132+
timeLineEvent.root.getClearType() == EventType.MESSAGE &&
133+
timeLineEvent.root.mxDecryptionResult?.isSafe == true
134134
}
135135
}
136136

@@ -302,6 +302,13 @@ class E2eeSanityTests : InstrumentedTest {
302302

303303
// ensure bob can now decrypt
304304
cryptoTestHelper.ensureCanDecrypt(sentEventIds, newBobSession, e2eRoomID, messagesText)
305+
306+
// Check key trust
307+
sentEventIds.forEach { sentEventId ->
308+
val timelineEvent = newBobSession.getRoom(e2eRoomID)?.getTimelineEvent(sentEventId)!!
309+
val result = newBobSession.cryptoService().decryptEvent(timelineEvent.root, "")
310+
assertEquals("Keys from history should be deniable", false, result.isSafe)
311+
}
305312
}
306313

307314
/**
@@ -348,42 +355,34 @@ class E2eeSanityTests : InstrumentedTest {
348355
Log.v("#E2E TEST", "check that new bob can't currently decrypt")
349356

350357
cryptoTestHelper.ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, null)
351-
// newBobSession.cryptoService().getOutgoingRoomKeyRequests()
352-
// .firstOrNull {
353-
// it.sessionId ==
354-
// }
355358

356359
// Try to request
357360
sentEventIds.forEach { sentEventId ->
358361
val event = newBobSession.getRoom(e2eRoomID)!!.getTimelineEvent(sentEventId)!!.root
359362
newBobSession.cryptoService().requestRoomKeyForEvent(event)
360363
}
361364

362-
// wait a bit
363-
// we need to wait a couple of syncs to let sharing occurs
364-
// testHelper.waitFewSyncs(newBobSession, 6)
365-
366365
// Ensure that new bob still can't decrypt (keys must have been withheld)
367-
sentEventIds.forEach { sentEventId ->
368-
val megolmSessionId = newBobSession.getRoom(e2eRoomID)!!
369-
.getTimelineEvent(sentEventId)!!
370-
.root.content.toModel<EncryptedEventContent>()!!.sessionId
371-
testHelper.retryPeriodically {
372-
val aliceReply = newBobSession.cryptoService().getOutgoingRoomKeyRequests()
373-
.first {
374-
it.sessionId == megolmSessionId &&
375-
it.roomId == e2eRoomID
376-
}
377-
.results.also {
378-
Log.w("##TEST", "result list is $it")
379-
}
380-
.firstOrNull { it.userId == aliceSession.myUserId }
381-
?.result
382-
aliceReply != null &&
383-
aliceReply is RequestResult.Failure &&
384-
WithHeldCode.UNAUTHORISED == aliceReply.code
385-
}
386-
}
366+
// sentEventIds.forEach { sentEventId ->
367+
// val megolmSessionId = newBobSession.getRoom(e2eRoomID)!!
368+
// .getTimelineEvent(sentEventId)!!
369+
// .root.content.toModel<EncryptedEventContent>()!!.sessionId
370+
// testHelper.retryPeriodically {
371+
// val aliceReply = newBobSession.cryptoService().getOutgoingRoomKeyRequests()
372+
// .first {
373+
// it.sessionId == megolmSessionId &&
374+
// it.roomId == e2eRoomID
375+
// }
376+
// .results.also {
377+
// Log.w("##TEST", "result list is $it")
378+
// }
379+
// .firstOrNull { it.userId == aliceSession.myUserId }
380+
// ?.result
381+
// aliceReply != null &&
382+
// aliceReply is RequestResult.Failure &&
383+
// WithHeldCode.UNAUTHORISED == aliceReply.code
384+
// }
385+
// }
387386

388387
cryptoTestHelper.ensureCannotDecrypt(sentEventIds, newBobSession, e2eRoomID, null)
389388

@@ -405,7 +404,10 @@ class E2eeSanityTests : InstrumentedTest {
405404
* Test that if a better key is forwarded (lower index, it is then used)
406405
*/
407406
@Test
408-
fun testForwardBetterKey() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
407+
fun testForwardBetterKey() = runCryptoTest(
408+
context(),
409+
cryptoConfig = MXCryptoConfig(limitRoomKeyRequestsToMyDevices = false)
410+
) { cryptoTestHelper, testHelper ->
409411

410412
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true)
411413
val aliceSession = cryptoTestData.firstSession

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/E2eeShareKeysHistoryTest.kt

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class E2eeShareKeysHistoryTest : InstrumentedTest {
7777
*/
7878
private fun testShareHistoryWithRoomVisibility(roomHistoryVisibility: RoomHistoryVisibility? = null) =
7979
runCryptoTest(context()) { cryptoTestHelper, testHelper ->
80+
val aliceMessageText = "Hello Bob, I am Alice!"
8081
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom(true, roomHistoryVisibility)
8182

8283
val e2eRoomID = cryptoTestData.roomId
@@ -96,20 +97,21 @@ class E2eeShareKeysHistoryTest : InstrumentedTest {
9697
assertEquals(bobRoomPOV.roomSummary()?.joinedMembersCount, 2)
9798
Log.v("#E2E TEST", "Alice and Bob are in roomId: $e2eRoomID")
9899

99-
val aliceMessageId: String? = sendMessageInRoom(aliceRoomPOV, "Hello Bob, I am Alice!", testHelper)
100+
val aliceMessageId: String? = sendMessageInRoom(aliceRoomPOV, aliceMessageText, testHelper)
100101
Assert.assertTrue("Message should be sent", aliceMessageId != null)
101102
Log.v("#E2E TEST", "Alice sent message to roomId: $e2eRoomID")
102103

103104
// Bob should be able to decrypt the message
104105
testHelper.retryPeriodically {
105-
val timelineEvent = bobSession.roomService().getRoom(e2eRoomID)?.timelineService()?.getTimelineEvent(aliceMessageId!!)
106-
(timelineEvent != null &&
107-
timelineEvent.isEncrypted() &&
108-
timelineEvent.root.getClearType() == EventType.MESSAGE).also {
109-
if (it) {
110-
Log.v("#E2E TEST", "Bob can decrypt the message: ${timelineEvent?.root?.getDecryptedTextSummary()}")
106+
val timelineEvent = bobSession.roomService().getRoom(e2eRoomID)?.timelineService()?.getTimelineEvent(aliceMessageId!!)
107+
(timelineEvent != null &&
108+
timelineEvent.isEncrypted() &&
109+
timelineEvent.root.getClearType() == EventType.MESSAGE &&
110+
timelineEvent.root.mxDecryptionResult?.isSafe == true).also {
111+
if (it) {
112+
Log.v("#E2E TEST", "Bob can decrypt the message: ${timelineEvent?.root?.getDecryptedTextSummary()}")
113+
}
111114
}
112-
}
113115
}
114116

115117
// Create a new user
@@ -134,15 +136,16 @@ class E2eeShareKeysHistoryTest : InstrumentedTest {
134136
-> {
135137
// Aris should be able to decrypt the message
136138
testHelper.retryPeriodically {
137-
val timelineEvent = arisSession.roomService().getRoom(e2eRoomID)?.timelineService()?.getTimelineEvent(aliceMessageId!!)
138-
(timelineEvent != null &&
139-
timelineEvent.isEncrypted() &&
140-
timelineEvent.root.getClearType() == EventType.MESSAGE
141-
).also {
142-
if (it) {
143-
Log.v("#E2E TEST", "Aris can decrypt the message: ${timelineEvent?.root?.getDecryptedTextSummary()}")
139+
val timelineEvent = arisSession.roomService().getRoom(e2eRoomID)?.timelineService()?.getTimelineEvent(aliceMessageId!!)
140+
(timelineEvent != null &&
141+
timelineEvent.isEncrypted() &&
142+
timelineEvent.root.getClearType() == EventType.MESSAGE &&
143+
timelineEvent.root.mxDecryptionResult?.isSafe == false
144+
).also {
145+
if (it) {
146+
Log.v("#E2E TEST", "Aris can decrypt the message: ${timelineEvent?.root?.getDecryptedTextSummary()}")
147+
}
144148
}
145-
}
146149
}
147150
}
148151
RoomHistoryVisibility.INVITED,
@@ -354,7 +357,10 @@ class E2eeShareKeysHistoryTest : InstrumentedTest {
354357
}
355358

356359
private suspend fun sendMessageInRoom(aliceRoomPOV: Room, text: String, testHelper: CommonTestHelper): String? {
357-
return testHelper.sendTextMessage(aliceRoomPOV, text, 1).firstOrNull()?.eventId
360+
return testHelper.sendTextMessage(aliceRoomPOV, text, 1).firstOrNull()?.let {
361+
Log.v("#E2E TEST", "Message sent with session ${it.root.content?.get("session_id")}")
362+
return it.eventId
363+
}
358364
}
359365

360366
private suspend fun ensureMembersHaveJoined(aliceSession: Session, otherAccounts: List<Session>, e2eRoomID: String, testHelper: CommonTestHelper) {

matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/internal/crypto/UnwedgingTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import org.matrix.android.sdk.api.auth.UIABaseAuth
3030
import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor
3131
import org.matrix.android.sdk.api.auth.UserPasswordAuth
3232
import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse
33+
import org.matrix.android.sdk.api.crypto.MXCryptoConfig
3334
import org.matrix.android.sdk.api.extensions.tryOrNull
3435
import org.matrix.android.sdk.api.session.crypto.MXCryptoError
3536
import org.matrix.android.sdk.api.session.events.model.EventType
@@ -82,7 +83,10 @@ class UnwedgingTest : InstrumentedTest {
8283
* -> This is automatically fixed after SDKs restarted the olm session
8384
*/
8485
@Test
85-
fun testUnwedging() = runCryptoTest(context()) { cryptoTestHelper, testHelper ->
86+
fun testUnwedging() = runCryptoTest(
87+
context(),
88+
cryptoConfig = MXCryptoConfig(limitRoomKeyRequestsToMyDevices = false)
89+
) { cryptoTestHelper, testHelper ->
8690
val cryptoTestData = cryptoTestHelper.doE2ETestWithAliceAndBobInARoom()
8791

8892
val aliceSession = cryptoTestData.firstSession

0 commit comments

Comments
 (0)