diff --git a/.github/workflows/jira-lint-and-link.yml b/.github/workflows/jira-lint-and-link.yml new file mode 100644 index 00000000000..54c2cb22544 --- /dev/null +++ b/.github/workflows/jira-lint-and-link.yml @@ -0,0 +1,19 @@ +name: Link and Lint PR with Jira Ticket Number +on: + merge_group: + pull_request: + types: [opened, edited, synchronize] +jobs: + add-jira-description: + runs-on: ubuntu-latest + # Run only if the PR is not from a Fork / external contributor + if: (!startsWith(github.ref, 'refs/heads/dependabot/') && github.repository_owner == 'wireapp') + steps: + - uses: cakeinpanic/jira-description-action@v0.8.0 + name: jira-description-action + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + jira-token: ${{ secrets.JIRA_TOKEN }} + jira-base-url: https://wearezeta.atlassian.net + skip-branches: '^(production-release|main|master|release\/v\d+)$' #optional + fail-when-jira-issue-not-found: false diff --git a/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt b/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt index 2f80972e470..e81b6fa10c2 100644 --- a/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt +++ b/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt @@ -22,14 +22,22 @@ import java.nio.file.Files actual open class BaseMLSClientTest { - actual suspend fun createMLSClient(clientId: CryptoQualifiedClientId): MLSClient { - return createCoreCrypto(clientId).mlsClient(clientId) + actual suspend fun createMLSClient( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): MLSClient { + return createCoreCrypto(clientId, allowedCipherSuites, defaultCipherSuite).mlsClient(clientId) } - actual suspend fun createCoreCrypto(clientId: CryptoQualifiedClientId): CoreCryptoCentral { + actual suspend fun createCoreCrypto( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): CoreCryptoCentral { val root = Files.createTempDirectory("mls").toFile() val keyStore = root.resolve("keystore-$clientId") - return coreCryptoCentral(keyStore.absolutePath, "test") + return coreCryptoCentral(keyStore.absolutePath, "test", allowedCipherSuites, defaultCipherSuite) } } diff --git a/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt b/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt index 7cdf4120f17..cfd85a6e8fe 100644 --- a/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt +++ b/cryptography/src/androidInstrumentedTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt @@ -34,7 +34,7 @@ actual open class BaseProteusClientTest { actual suspend fun createProteusClient(proteusStore: ProteusStoreRef, databaseKey: ProteusDBSecret?): ProteusClient { return databaseKey?.let { - coreCryptoCentral(proteusStore.value, it.value).proteusClient() + coreCryptoCentral(proteusStore.value, it.value, emptyList(), 0.toUShort()).proteusClient() } ?: cryptoboxProteusClient(proteusStore.value, testCoroutineScheduler, testCoroutineScheduler) } } diff --git a/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt b/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt index a3e415e6914..f713c82dfa7 100644 --- a/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt +++ b/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt @@ -21,13 +21,21 @@ package com.wire.kalium.cryptography import java.nio.file.Files actual open class BaseMLSClientTest { - actual suspend fun createMLSClient(clientId: CryptoQualifiedClientId): MLSClient { - return createCoreCrypto(clientId).mlsClient(clientId) + actual suspend fun createMLSClient( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): MLSClient { + return createCoreCrypto(clientId, allowedCipherSuites, defaultCipherSuite).mlsClient(clientId) } - actual suspend fun createCoreCrypto(clientId: CryptoQualifiedClientId): CoreCryptoCentral { + actual suspend fun createCoreCrypto( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): CoreCryptoCentral { val root = Files.createTempDirectory("mls").toFile() val keyStore = root.resolve("keystore-$clientId") - return coreCryptoCentral(keyStore.absolutePath, "test") + return coreCryptoCentral(keyStore.absolutePath, "test", allowedCipherSuites, defaultCipherSuite) } } diff --git a/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt b/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt index 5e686e24443..20b5c3f3658 100644 --- a/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt +++ b/cryptography/src/androidUnitTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt @@ -33,7 +33,7 @@ actual open class BaseProteusClientTest { actual suspend fun createProteusClient(proteusStore: ProteusStoreRef, databaseKey: ProteusDBSecret?): ProteusClient { return databaseKey?.let { - coreCryptoCentral(proteusStore.value, it.value).proteusClient() + coreCryptoCentral(proteusStore.value, it.value, emptyList(), null).proteusClient() } ?: cryptoboxProteusClient(proteusStore.value, testCoroutineScheduler,testCoroutineScheduler) } } diff --git a/cryptography/src/appleMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt b/cryptography/src/appleMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt index 52dd4c07f96..259c4e54dc5 100644 --- a/cryptography/src/appleMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt +++ b/cryptography/src/appleMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt @@ -24,7 +24,12 @@ import com.wire.crypto.CoreCryptoCallbacks import platform.Foundation.NSFileManager import kotlin.time.Duration -actual suspend fun coreCryptoCentral(rootDir: String, databaseKey: String): CoreCryptoCentral { +actual suspend fun coreCryptoCentral( + rootDir: String, + databaseKey: String, + allowedCipherSuites: List, + defaultCipherSuite: UShort? +): CoreCryptoCentral { val path = "$rootDir/${CoreCryptoCentralImpl.KEYSTORE_NAME}" NSFileManager.defaultManager.createDirectoryAtPath(rootDir, withIntermediateDirectories = true, null, null) val coreCrypto = CoreCrypto.deferredInit(path, databaseKey, null) diff --git a/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt b/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt index 7ab8ae14087..dbdb6e0bf3a 100644 --- a/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt +++ b/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt @@ -24,14 +24,22 @@ import platform.Foundation.NSURL import platform.Foundation.URLByAppendingPathComponent actual open class BaseMLSClientTest actual constructor() { - actual suspend fun createMLSClient(clientId: CryptoQualifiedClientId): MLSClient { - return createCoreCrypto(clientId).mlsClient(clientId) + actual suspend fun createMLSClient( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): MLSClient { + return createCoreCrypto(clientId, allowedCipherSuites, defaultCipherSuite).mlsClient(clientId) } - actual suspend fun createCoreCrypto(clientId: CryptoQualifiedClientId): CoreCryptoCentral { + actual suspend fun createCoreCrypto( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): CoreCryptoCentral { val rootDir = NSURL.fileURLWithPath(NSTemporaryDirectory() + "/mls", isDirectory = true) NSFileManager.defaultManager.createDirectoryAtURL(rootDir, true, null, null) val keyStore = rootDir.URLByAppendingPathComponent("keystore-$clientId")!! - return coreCryptoCentral(keyStore.path!!, "test") + return coreCryptoCentral(keyStore.path!!, "test", allowedCipherSuites, defaultCipherSuite) } } diff --git a/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt b/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt index 81a1a2f72e5..23b47c90120 100644 --- a/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt +++ b/cryptography/src/appleTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt @@ -35,7 +35,7 @@ actual open class BaseProteusClientTest actual constructor() { proteusStore: ProteusStoreRef, databaseKey: ProteusDBSecret? ): ProteusClient { - return coreCryptoCentral(proteusStore.value, "secret").proteusClient() + return coreCryptoCentral(proteusStore.value, "secret", emptyList(), null).proteusClient() } } diff --git a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt index 465302eea90..5eefcb16f63 100644 --- a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt +++ b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/CoreCryptoCentral.kt @@ -17,21 +17,31 @@ */ package com.wire.kalium.cryptography +import com.wire.crypto.Ciphersuites import com.wire.crypto.ClientId import com.wire.crypto.CoreCrypto import com.wire.crypto.CoreCryptoCallbacks -import com.wire.crypto.client.Ciphersuites import com.wire.crypto.coreCryptoDeferredInit import com.wire.kalium.cryptography.MLSClientImpl.Companion.toCrlRegistration import com.wire.kalium.cryptography.exceptions.CryptographyException import java.io.File -actual suspend fun coreCryptoCentral(rootDir: String, databaseKey: String): CoreCryptoCentral { +actual suspend fun coreCryptoCentral( + rootDir: String, + databaseKey: String, + allowedCipherSuites: Ciphersuites, + defaultCipherSuite: UShort? +): CoreCryptoCentral { val path = "$rootDir/${CoreCryptoCentralImpl.KEYSTORE_NAME}" File(rootDir).mkdirs() - val coreCrypto = coreCryptoDeferredInit(path, databaseKey, Ciphersuites.DEFAULT.lower(), null) + val coreCrypto = coreCryptoDeferredInit(path, databaseKey, allowedCipherSuites, null) coreCrypto.setCallbacks(Callbacks()) - return CoreCryptoCentralImpl(coreCrypto, rootDir) + return CoreCryptoCentralImpl( + cc = coreCrypto, + rootDir = rootDir, + cipherSuite = allowedCipherSuites, + defaultCipherSuite = defaultCipherSuite + ) } private class Callbacks : CoreCryptoCallbacks { @@ -61,12 +71,18 @@ private class Callbacks : CoreCryptoCallbacks { } } -class CoreCryptoCentralImpl(private val cc: CoreCrypto, private val rootDir: String) : CoreCryptoCentral { +class CoreCryptoCentralImpl( + private val cc: CoreCrypto, + private val rootDir: String, + // TODO: remove one they are removed from the CC api + private val cipherSuite: Ciphersuites, + private val defaultCipherSuite: UShort? +) : CoreCryptoCentral { fun getCoreCrypto() = cc override suspend fun mlsClient(clientId: CryptoQualifiedClientId): MLSClient { - cc.mlsInit(clientId.toString().encodeToByteArray(), Ciphersuites.DEFAULT.lower(), null) - return MLSClientImpl(cc) + cc.mlsInit(clientId.toString().encodeToByteArray(), cipherSuite, null) + return MLSClientImpl(cc, defaultCipherSuite!!) } override suspend fun mlsClient( @@ -79,7 +95,7 @@ class CoreCryptoCentralImpl(private val cc: CoreCrypto, private val rootDir: Str (enrollment as E2EIClientImpl).wireE2eIdentity, certificateChain, newMLSKeyPackageCount ) - return MLSClientImpl(cc) + return MLSClientImpl(cc, defaultCipherSuite!!) } override suspend fun proteusClient(): ProteusClient { @@ -100,7 +116,7 @@ class CoreCryptoCentralImpl(private val cc: CoreCrypto, private val rootDir: Str handle, teamId, expiry.inWholeSeconds.toUInt(), - Ciphersuites.DEFAULT.lower().first() + defaultCipherSuite!! ) ) diff --git a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/MLSClientImpl.kt b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/MLSClientImpl.kt index 6e442fb6c09..0bfa6b1dada 100644 --- a/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/MLSClientImpl.kt +++ b/cryptography/src/commonJvmAndroid/kotlin/com.wire.kalium.cryptography/MLSClientImpl.kt @@ -28,7 +28,7 @@ import com.wire.crypto.MlsCredentialType import com.wire.crypto.MlsGroupInfoEncryptionType import com.wire.crypto.MlsRatchetTreeType import com.wire.crypto.MlsWirePolicy -import com.wire.crypto.client.Ciphersuites +import com.wire.crypto.Ciphersuite import io.ktor.util.decodeBase64Bytes import io.ktor.util.encodeBase64 import kotlin.time.Duration @@ -41,25 +41,26 @@ typealias ConversationId = ByteArray @Suppress("TooManyFunctions") @OptIn(ExperimentalUnsignedTypes::class) class MLSClientImpl( - private val coreCrypto: CoreCrypto + private val coreCrypto: CoreCrypto, + private val defaultCipherSuite: Ciphersuite ) : MLSClient { private val keyRotationDuration: Duration = 30.toDuration(DurationUnit.DAYS) private val defaultGroupConfiguration = CustomConfiguration(keyRotationDuration.toJavaDuration(), MlsWirePolicy.PLAINTEXT) - private val defaultCiphersuite = Ciphersuites.DEFAULT.lower().first() + override suspend fun close() { coreCrypto.close() } override suspend fun getPublicKey(): ByteArray { - return coreCrypto.clientPublicKey(defaultCiphersuite, toCredentialType(getMLSCredentials())) + return coreCrypto.clientPublicKey(defaultCipherSuite, toCredentialType(getMLSCredentials())) } override suspend fun generateKeyPackages(amount: Int): List { - return coreCrypto.clientKeypackages(defaultCiphersuite, toCredentialType(getMLSCredentials()), amount.toUInt()) + return coreCrypto.clientKeypackages(defaultCipherSuite, toCredentialType(getMLSCredentials()), amount.toUInt()) } override suspend fun validKeyPackageCount(): ULong { - return coreCrypto.clientValidKeypackagesCount(defaultCiphersuite, toCredentialType(getMLSCredentials())) + return coreCrypto.clientValidKeypackagesCount(defaultCipherSuite, toCredentialType(getMLSCredentials())) } override suspend fun updateKeyingMaterial(groupId: MLSGroupId): CommitBundle { @@ -78,7 +79,7 @@ class MLSClientImpl( return coreCrypto.newExternalAddProposal( conversationId = groupId.decodeBase64Bytes(), epoch = epoch, - ciphersuite = defaultCiphersuite, + ciphersuite = defaultCipherSuite, credentialType = toCredentialType(getMLSCredentials()) ) } @@ -106,7 +107,7 @@ class MLSClientImpl( externalSenders: List ) { val conf = ConversationConfiguration( - defaultCiphersuite, + defaultCipherSuite, externalSenders.map { it.value }, defaultGroupConfiguration ) @@ -210,7 +211,7 @@ class MLSClientImpl( handle, teamId, expiry.inWholeSeconds.toUInt(), - defaultCiphersuite + defaultCipherSuite ) ) } @@ -227,7 +228,7 @@ class MLSClientImpl( handle, teamId, expiry.inWholeSeconds.toUInt(), - defaultCiphersuite + defaultCipherSuite ) ) } @@ -237,7 +238,7 @@ class MLSClientImpl( } override suspend fun isE2EIEnabled(): Boolean { - return coreCrypto.e2eiIsEnabled(defaultCiphersuite) + return coreCrypto.e2eiIsEnabled(defaultCipherSuite) } override suspend fun getMLSCredentials(): CredentialType { diff --git a/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentral.kt b/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentral.kt index eabd9acc4a5..10fc3146a48 100644 --- a/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentral.kt +++ b/cryptography/src/commonMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentral.kt @@ -22,7 +22,11 @@ import kotlin.time.Duration interface CoreCryptoCentral { suspend fun mlsClient(clientId: CryptoQualifiedClientId): MLSClient - suspend fun mlsClient(enrollment: E2EIClient, certificateChain: CertificateChain, newMLSKeyPackageCount: UInt): MLSClient + suspend fun mlsClient( + enrollment: E2EIClient, + certificateChain: CertificateChain, + newMLSKeyPackageCount: UInt + ): MLSClient suspend fun proteusClient(): ProteusClient @@ -59,4 +63,9 @@ interface CoreCryptoCentral { suspend fun registerIntermediateCa(pem: CertificateChain) } -expect suspend fun coreCryptoCentral(rootDir: String, databaseKey: String): CoreCryptoCentral +expect suspend fun coreCryptoCentral( + rootDir: String, + databaseKey: String, + allowedCipherSuites: List, + defaultCipherSuite: UShort? +): CoreCryptoCentral diff --git a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt index e3fc901cf0a..7957f86f271 100644 --- a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt +++ b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt @@ -20,8 +20,16 @@ package com.wire.kalium.cryptography expect open class BaseMLSClientTest() { - suspend fun createMLSClient(clientId: CryptoQualifiedClientId): MLSClient + suspend fun createMLSClient( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): MLSClient - suspend fun createCoreCrypto(clientId: CryptoQualifiedClientId): CoreCryptoCentral + suspend fun createCoreCrypto( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): CoreCryptoCentral } diff --git a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/E2EIClientTest.kt b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/E2EIClientTest.kt index ece85e201ad..3863baca4ea 100644 --- a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/E2EIClientTest.kt +++ b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/E2EIClientTest.kt @@ -35,7 +35,7 @@ class E2EIClientTest : BaseMLSClientTest() { } private suspend fun createE2EIClient(user: SampleUser): E2EIClient { - return createMLSClient(user.qualifiedClientId).e2eiNewActivationEnrollment( + return createMLSClient(user.qualifiedClientId, ALLOWED_CIPHER_SUITES, DEFAULT_CIPHER_SUITE).e2eiNewActivationEnrollment( user.name, user.handle, user.teamId,90.days ) } @@ -112,7 +112,7 @@ class E2EIClientTest : BaseMLSClientTest() { @Test fun givenClient_whenCallingCheckOrderRequest_ReturnNonEmptyResult() = runTest { - val coreCryptoCentral = createCoreCrypto(ALICE1.qualifiedClientId) + val coreCryptoCentral = createCoreCrypto(ALICE1.qualifiedClientId, ALLOWED_CIPHER_SUITES, DEFAULT_CIPHER_SUITE) val e2eiClient = createE2EIClient(ALICE1) e2eiClient.directoryResponse(ACME_DIRECTORY_API_RESPONSE) e2eiClient.setAccountResponse(NEW_ACCOUNT_API_RESPONSE) @@ -130,7 +130,7 @@ class E2EIClientTest : BaseMLSClientTest() { @Test fun givenClient_whenCallingFinalizeRequest_ReturnNonEmptyResult() = runTest { - val coreCryptoCentral = createCoreCrypto(ALICE1.qualifiedClientId) + val coreCryptoCentral = createCoreCrypto(ALICE1.qualifiedClientId, ALLOWED_CIPHER_SUITES, DEFAULT_CIPHER_SUITE) val e2eiClient = createE2EIClient(ALICE1) e2eiClient.directoryResponse(ACME_DIRECTORY_API_RESPONSE) e2eiClient.setAccountResponse(NEW_ACCOUNT_API_RESPONSE) @@ -149,7 +149,7 @@ class E2EIClientTest : BaseMLSClientTest() { @Test fun givenClient_whenCallingCertificateRequest_ReturnNonEmptyResult() = runTest { - val coreCryptoCentral = createCoreCrypto(ALICE1.qualifiedClientId) + val coreCryptoCentral = createCoreCrypto(ALICE1.qualifiedClientId, ALLOWED_CIPHER_SUITES, DEFAULT_CIPHER_SUITE) val e2eiClient = createE2EIClient(ALICE1) e2eiClient.directoryResponse(ACME_DIRECTORY_API_RESPONSE) e2eiClient.setAccountResponse(NEW_ACCOUNT_API_RESPONSE) @@ -169,6 +169,8 @@ class E2EIClientTest : BaseMLSClientTest() { companion object { + val DEFAULT_CIPHER_SUITE = 1.toUShort() + val ALLOWED_CIPHER_SUITES = listOf(1.toUShort()) val ALICE1 = SampleUser( CryptoQualifiedID("837655f7-b448-465a-b4b2-93f0919b38f0", "elna.wire.link"), CryptoClientId("fb4b58152e20"), diff --git a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/MLSClientTest.kt b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/MLSClientTest.kt index 93b8723740d..861007a7609 100644 --- a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/MLSClientTest.kt +++ b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/MLSClientTest.kt @@ -33,7 +33,7 @@ class MLSClientTest : BaseMLSClientTest() { } private suspend fun createClient(user: SampleUser): MLSClient { - return createMLSClient(user.qualifiedClientId) + return createMLSClient(user.qualifiedClientId, ALLOWED_CIPHER_SUITES, DEFAULT_CIPHER_SUITES) } @Test @@ -188,6 +188,8 @@ class MLSClientTest : BaseMLSClientTest() { } companion object { + val ALLOWED_CIPHER_SUITES = listOf(1.toUShort()) + val DEFAULT_CIPHER_SUITES = 1.toUShort() const val MLS_CONVERSATION_ID = "JfflcPtUivbg+1U3Iyrzsh5D2ui/OGS5Rvf52ipH5KY=" const val PLAIN_TEXT = "Hello World" val ALICE1 = SampleUser( diff --git a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/ProteusClientTest.kt b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/ProteusClientTest.kt index 4260020978a..82eca15fece 100644 --- a/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/ProteusClientTest.kt +++ b/cryptography/src/commonTest/kotlin/com/wire/kalium/cryptography/ProteusClientTest.kt @@ -1,4 +1,4 @@ -/* + /* * Wire * Copyright (C) 2024 Wire Swiss GmbH * diff --git a/cryptography/src/jsMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt b/cryptography/src/jsMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt index 8a609a1e420..1e007c05b53 100644 --- a/cryptography/src/jsMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt +++ b/cryptography/src/jsMain/kotlin/com/wire/kalium/cryptography/CoreCryptoCentralImpl.kt @@ -17,4 +17,9 @@ */ package com.wire.kalium.cryptography -actual suspend fun coreCryptoCentral(rootDir: String, databaseKey: String): CoreCryptoCentral = TODO("Not yet implemented") +actual suspend fun coreCryptoCentral( + rootDir: String, + databaseKey: String, + allowedCipherSuites: List, + defaultCipherSuite: UShort? +): CoreCryptoCentral = TODO("Not yet implemented") diff --git a/cryptography/src/jsTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt b/cryptography/src/jsTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt index a47c5b0bd37..32d073968a9 100644 --- a/cryptography/src/jsTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt +++ b/cryptography/src/jsTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt @@ -19,11 +19,19 @@ package com.wire.kalium.cryptography actual open class BaseMLSClientTest actual constructor() { - actual suspend fun createMLSClient(clientId: CryptoQualifiedClientId): MLSClient { + actual suspend fun createMLSClient( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): MLSClient { TODO("Not yet implemented") } - actual suspend fun createCoreCrypto(clientId: CryptoQualifiedClientId):CoreCryptoCentral { + actual suspend fun createCoreCrypto( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): CoreCryptoCentral { TODO("Not yet implemented") } } diff --git a/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt b/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt index fe5b4c14f34..e8f67f7377d 100644 --- a/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt +++ b/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseMLSClientTest.kt @@ -22,13 +22,21 @@ import java.nio.file.Files actual open class BaseMLSClientTest { - actual suspend fun createMLSClient(clientId: CryptoQualifiedClientId): MLSClient { - return createCoreCrypto(clientId).mlsClient(clientId) + actual suspend fun createMLSClient( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): MLSClient { + return createCoreCrypto(clientId, allowedCipherSuites, defaultCipherSuite).mlsClient(clientId) } - actual suspend fun createCoreCrypto(clientId: CryptoQualifiedClientId): CoreCryptoCentral { + actual suspend fun createCoreCrypto( + clientId: CryptoQualifiedClientId, + allowedCipherSuites: List, + defaultCipherSuite: UShort + ): CoreCryptoCentral { val root = Files.createTempDirectory("mls").toFile() val keyStore = root.resolve("keystore-$clientId") - return coreCryptoCentral(keyStore.absolutePath, "test") + return coreCryptoCentral(keyStore.absolutePath, "test", allowedCipherSuites, defaultCipherSuite) } } diff --git a/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt b/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt index 5e686e24443..20b5c3f3658 100644 --- a/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt +++ b/cryptography/src/jvmTest/kotlin/com/wire/kalium/cryptography/BaseProteusClientTest.kt @@ -33,7 +33,7 @@ actual open class BaseProteusClientTest { actual suspend fun createProteusClient(proteusStore: ProteusStoreRef, databaseKey: ProteusDBSecret?): ProteusClient { return databaseKey?.let { - coreCryptoCentral(proteusStore.value, it.value).proteusClient() + coreCryptoCentral(proteusStore.value, it.value, emptyList(), null).proteusClient() } ?: cryptoboxProteusClient(proteusStore.value, testCoroutineScheduler,testCoroutineScheduler) } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c1bf2e8639a..0ef8535231d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -38,7 +38,7 @@ pbandk = "0.14.2" turbine = "1.1.0" avs = "9.7.12" jna = "5.14.0" -core-crypto = "1.0.0-rc.55" +core-crypto = "1.0.0-rc.56-hotfix.1" core-crypto-multiplatform = "0.6.0-rc.3-multiplatform-pre1" completeKotlin = "1.1.0" desugar-jdk = "2.0.4" diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt index 1041832636e..e0fb55441ac 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/configuration/UserConfigRepository.kt @@ -28,6 +28,8 @@ import com.wire.kalium.logic.data.legalhold.LegalHoldRequest import com.wire.kalium.logic.data.message.SelfDeletionMapper.toSelfDeletionTimerEntity import com.wire.kalium.logic.data.message.SelfDeletionMapper.toTeamSelfDeleteTimer import com.wire.kalium.logic.data.message.TeamSettingsSelfDeletionStatus +import com.wire.kalium.logic.data.mls.CipherSuite +import com.wire.kalium.logic.data.mls.SupportedCipherSuite import com.wire.kalium.logic.data.user.SupportedProtocol import com.wire.kalium.logic.data.user.toDao import com.wire.kalium.logic.data.user.toModel @@ -44,6 +46,7 @@ import com.wire.kalium.persistence.config.IsFileSharingEnabledEntity import com.wire.kalium.persistence.config.TeamSettingsSelfDeletionStatusEntity import com.wire.kalium.persistence.config.UserConfigStorage import com.wire.kalium.persistence.dao.unread.UserConfigDAO +import com.wire.kalium.persistence.model.SupportedCipherSuiteEntity import com.wire.kalium.util.DateTimeUtil import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map @@ -83,6 +86,8 @@ interface UserConfigRepository { fun setE2EISettings(setting: E2EISettings): Either fun snoozeE2EINotification(duration: Duration): Either fun setDefaultProtocol(protocol: SupportedProtocol): Either + suspend fun setSupportedCipherSuite(cipherSuite: SupportedCipherSuite): Either + suspend fun getSupportedCipherSuite(): Either fun getDefaultProtocol(): Either suspend fun setSupportedProtocols(protocols: Set): Either suspend fun getSupportedProtocols(): Either> @@ -249,6 +254,25 @@ internal class UserConfigDataSource internal constructor( override fun setDefaultProtocol(protocol: SupportedProtocol): Either = wrapStorageRequest { userConfigStorage.persistDefaultProtocol(protocol.toDao()) } + override suspend fun setSupportedCipherSuite(cipherSuite: SupportedCipherSuite): Either = + SupportedCipherSuiteEntity( + supported = cipherSuite.supported.map { it.tag }, + default = cipherSuite.default.tag + ).let { + wrapStorageRequest { + userConfigDAO.setDefaultCipherSuite(it) + } + } + + override suspend fun getSupportedCipherSuite(): Either = wrapStorageRequest { + userConfigDAO.getDefaultCipherSuite() + }.map { + SupportedCipherSuite( + supported = it.supported.map { tag -> CipherSuite.fromTag(tag) }, + default = CipherSuite.fromTag(it.default) + ) + } + override fun getDefaultProtocol(): Either = wrapStorageRequest { userConfigStorage.defaultProtocol().toModel() } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/E2EIClientProvider.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/E2EIClientProvider.kt index ec53963aa41..b115a3dcd8d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/E2EIClientProvider.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/E2EIClientProvider.kt @@ -76,11 +76,11 @@ internal class EI2EIClientProviderImpl( selfUser.id.toCrypto() ) val newE2EIClient = it.newAcmeEnrollment( - cryptoQualifiedClientId, - selfUser.name!!, - selfUser.handle!!, - selfUser.teamId?.value, - defaultE2EIExpiry + clientId = cryptoQualifiedClientId, + displayName = selfUser.name!!, + handle = selfUser.handle!!, + teamId = selfUser.teamId?.value, + expiry = defaultE2EIExpiry ) e2EIClient = newE2EIClient Either.Right(newE2EIClient) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/MLSClientProvider.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/MLSClientProvider.kt index e62e82725e2..d41ef34e27d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/MLSClientProvider.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/MLSClientProvider.kt @@ -28,11 +28,13 @@ import com.wire.kalium.cryptography.coreCryptoCentral import com.wire.kalium.logger.KaliumLogLevel import com.wire.kalium.logic.CoreFailure import com.wire.kalium.logic.E2EIFailure +import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.conversation.ClientId import com.wire.kalium.logic.data.id.CurrentClientIdProvider import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.functional.Either import com.wire.kalium.logic.functional.fold +import com.wire.kalium.logic.functional.getOrElse import com.wire.kalium.logic.functional.left import com.wire.kalium.logic.functional.map import com.wire.kalium.logic.functional.right @@ -48,7 +50,7 @@ import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext interface MLSClientProvider { - fun isMLSClientInitialised(): Boolean + suspend fun isMLSClientInitialised(): Boolean suspend fun getMLSClient(clientId: ClientId? = null): Either @@ -67,6 +69,7 @@ class MLSClientProviderImpl( private val userId: UserId, private val currentClientIdProvider: CurrentClientIdProvider, private val passphraseStorage: PassphraseStorage, + private val userConfigRepository: UserConfigRepository, private val dispatchers: KaliumDispatcher = KaliumDispatcherImpl ) : MLSClientProvider { @@ -76,7 +79,7 @@ class MLSClientProviderImpl( private val mlsClientMutex = Mutex() private val coreCryptoCentralMutex = Mutex() - override fun isMLSClientInitialised() = mlsClient != null + override suspend fun isMLSClientInitialised() = mlsClientMutex.withLock { mlsClient != null } override suspend fun getMLSClient(clientId: ClientId?): Either = mlsClientMutex.withLock { withContext(dispatchers.io) { @@ -127,8 +130,11 @@ class MLSClientProviderImpl( } @Suppress("TooGenericExceptionCaught") - override suspend fun getCoreCrypto(clientId: ClientId?) = coreCryptoCentralMutex.withLock { + override suspend fun getCoreCrypto(clientId: ClientId?): Either = coreCryptoCentralMutex.withLock { withContext(dispatchers.io) { + val (supportedCipherSuite, defaultCipherSuite) = userConfigRepository.getSupportedCipherSuite() + .getOrElse { return@withContext Either.Left(it) } + val currentClientId = clientId ?: currentClientIdProvider().fold({ return@withContext Either.Left(it) }, { it }) val location = "$rootKeyStorePath/${currentClientId.value}".also { @@ -142,7 +148,9 @@ class MLSClientProviderImpl( val cc = try { coreCryptoCentral( rootDir = "$location/$KEYSTORE_NAME", - databaseKey = passphrase + databaseKey = passphrase, + allowedCipherSuites = supportedCipherSuite.map { it.tag.toUShort() }, + defaultCipherSuite = defaultCipherSuite.tag.toUShort() ) } catch (e: Exception) { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/ProteusClientProvider.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/ProteusClientProvider.kt index 013deac601f..f697f679eed 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/ProteusClientProvider.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/client/ProteusClientProvider.kt @@ -106,7 +106,9 @@ class ProteusClientProviderImpl( val central = try { coreCryptoCentral( rootDir = rootProteusPath, - databaseKey = SecurityHelperImpl(passphraseStorage).proteusDBSecret(userId).value + databaseKey = SecurityHelperImpl(passphraseStorage).proteusDBSecret(userId).value, + allowedCipherSuites = emptyList(), + defaultCipherSuite = null ) } catch (e: Exception) { diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/Conversation.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/Conversation.kt index 1145d76bd20..afdd57f3832 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/Conversation.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/Conversation.kt @@ -29,6 +29,7 @@ import com.wire.kalium.logic.data.id.PlainId import com.wire.kalium.logic.data.id.TeamId import com.wire.kalium.logic.data.message.MessagePreview import com.wire.kalium.logic.data.message.UnreadEventType +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.data.user.OtherUser import com.wire.kalium.logic.data.user.User import com.wire.kalium.logic.data.user.UserId @@ -195,23 +196,6 @@ data class Conversation( enum class VerificationStatus { VERIFIED, NOT_VERIFIED, DEGRADED } enum class LegalHoldStatus { ENABLED, DISABLED, DEGRADED, UNKNOWN } - @Suppress("MagicNumber") - enum class CipherSuite(val tag: Int) { - UNKNOWN(0), - MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519(1), - MLS_128_DHKEMP256_AES128GCM_SHA256_P256(2), - MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519(3), - MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448(4), - MLS_256_DHKEMP521_AES256GCM_SHA512_P521(5), - MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448(6), - MLS_256_DHKEMP384_AES256GCM_SHA384_P384(7), - MLS_128_X25519KYBER768DRAFT00_AES128GCM_SHA256_ED25519(61489); - - companion object { - fun fromTag(tag: Int): CipherSuite = values().first { type -> type.tag == tag } - } - } - val supportsUnreadMessageCount get() = type in setOf(Type.ONE_ON_ONE, Type.GROUP) @@ -236,7 +220,7 @@ data class Conversation( "groupState" to groupState.name, "epoch" to "$epoch", "keyingMaterialLastUpdate" to keyingMaterialLastUpdate.toString(), - "cipherSuite" to cipherSuite.name + "cipherSuite" to cipherSuite.toString() ) } @@ -254,7 +238,7 @@ data class Conversation( "groupState" to groupState.name, "epoch" to "$epoch", "keyingMaterialLastUpdate" to keyingMaterialLastUpdate.toString(), - "cipherSuite" to cipherSuite.name + "cipherSuite" to cipherSuite.toString() ) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapper.kt index 02ec6f130d0..f09e64fc004 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapper.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapper.kt @@ -19,6 +19,7 @@ package com.wire.kalium.logic.data.conversation import com.wire.kalium.logic.data.id.IdMapper +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.di.MapperProvider import com.wire.kalium.persistence.dao.conversation.ConversationEntity @@ -38,14 +39,14 @@ class ProtocolInfoMapperImpl( Conversation.ProtocolInfo.MLSCapable.GroupState.valueOf(protocolInfo.groupState.name), protocolInfo.epoch, protocolInfo.keyingMaterialLastUpdate, - Conversation.CipherSuite.fromTag(protocolInfo.cipherSuite.cipherSuiteTag) + CipherSuite.fromTag(protocolInfo.cipherSuite.cipherSuiteTag) ) is ConversationEntity.ProtocolInfo.Mixed -> Conversation.ProtocolInfo.Mixed( idMapper.fromGroupIDEntity(protocolInfo.groupId), Conversation.ProtocolInfo.MLSCapable.GroupState.valueOf(protocolInfo.groupState.name), protocolInfo.epoch, protocolInfo.keyingMaterialLastUpdate, - Conversation.CipherSuite.fromTag(protocolInfo.cipherSuite.cipherSuiteTag) + CipherSuite.fromTag(protocolInfo.cipherSuite.cipherSuiteTag) ) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigMapper.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigMapper.kt index cf6962f16b6..7f3dcc0b7a2 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigMapper.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigMapper.kt @@ -18,6 +18,8 @@ package com.wire.kalium.logic.data.featureConfig +import com.wire.kalium.logic.data.mls.CipherSuite +import com.wire.kalium.logic.data.mls.SupportedCipherSuite import com.wire.kalium.logic.data.user.SupportedProtocol import com.wire.kalium.logic.data.user.toModel import com.wire.kalium.network.api.base.authenticated.featureConfigs.FeatureConfigData @@ -76,14 +78,19 @@ class FeatureConfigMapperImpl : FeatureConfigMapper { override fun fromDTO(data: FeatureConfigData.MLS?): MLSModel = data?.let { MLSModel( - it.config.defaultProtocol.toModel(), - it.config.supportedProtocols.map { it.toModel() }.toSet(), - fromDTO(it.status) + defaultProtocol = it.config.defaultProtocol.toModel(), + supportedProtocols = it.config.supportedProtocols.map { it.toModel() }.toSet(), + status = fromDTO(it.status), + supportedCipherSuite = SupportedCipherSuite( + default = CipherSuite.fromTag(it.config.defaultCipherSuite), + supported = it.config.allowedCipherSuites.map { CipherSuite.fromTag(it) } + ) ) } ?: MLSModel( - SupportedProtocol.PROTEUS, - setOf(SupportedProtocol.PROTEUS), - Status.DISABLED + defaultProtocol = SupportedProtocol.PROTEUS, + supportedCipherSuite = null, + supportedProtocols = setOf(SupportedProtocol.PROTEUS), + status = Status.DISABLED ) @Suppress("MagicNumber") diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigModel.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigModel.kt index f90d4818f8d..6391b7d6378 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigModel.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigModel.kt @@ -18,6 +18,7 @@ package com.wire.kalium.logic.data.featureConfig +import com.wire.kalium.logic.data.mls.SupportedCipherSuite import com.wire.kalium.logic.data.user.SupportedProtocol import com.wire.kalium.util.time.Second import kotlinx.datetime.Instant @@ -78,6 +79,7 @@ data class SelfDeletingMessagesConfigModel( data class MLSModel( val defaultProtocol: SupportedProtocol, val supportedProtocols: Set, + val supportedCipherSuite: SupportedCipherSuite?, val status: Status ) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/mls/CipherSuite.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/mls/CipherSuite.kt new file mode 100644 index 00000000000..161a24b4f09 --- /dev/null +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/data/mls/CipherSuite.kt @@ -0,0 +1,98 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.logic.data.mls + +data class SupportedCipherSuite( + val supported: List, + val default: CipherSuite +) + +@Suppress("MagicNumber", "ClassName") +sealed class CipherSuite(open val tag: Int) { + data class UNKNOWN(override val tag: Int) : CipherSuite(tag) { + override fun toString(): String { + return "UNKNOWN($tag)".uppercase() + } + } + + data object MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 : CipherSuite(1) { + override fun toString(): String { + return "MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519" + } + } + + data object MLS_128_DHKEMP256_AES128GCM_SHA256_P256 : CipherSuite(2) { + override fun toString(): String { + return "MLS_128_DHKEMP256_AES128GCM_SHA256_P256" + } + } + + data object MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 : + CipherSuite(3) { + override fun toString(): String { + return "MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519" + } + } + + data object MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 : CipherSuite(4) { + override fun toString(): String { + return "MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448" + + } + } + + data object MLS_256_DHKEMP521_AES256GCM_SHA512_P521 : CipherSuite(5) { + override fun toString(): String { + return "MLS_256_DHKEMP521_AES256GCM_SHA512_P521" + } + + } + + data object MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 : CipherSuite(6) { + override fun toString(): String { + return "MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448" + } + } + + data object MLS_256_DHKEMP384_AES256GCM_SHA384_P384 : CipherSuite(7) { + override fun toString(): String { + return "MLS_256_DHKEMP384_AES256GCM_SHA384_P384" + } + } + + data object MLS_128_X25519KYBER768DRAFT00_AES128GCM_SHA256_ED25519 : + CipherSuite(61489) { + override fun toString(): String { + return "MLS_128_X25519KYBER768DRAFT00_AES128GCM_SHA256_ED25519" + } + } + + companion object { + fun fromTag(tag: Int): CipherSuite = when (tag) { + 1 -> MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + 2 -> MLS_128_DHKEMP256_AES128GCM_SHA256_P256 + 3 -> MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519 + 4 -> MLS_256_DHKEMX448_AES256GCM_SHA512_Ed448 + 5 -> MLS_256_DHKEMP521_AES256GCM_SHA512_P521 + 6 -> MLS_256_DHKEMX448_CHACHA20POLY1305_SHA512_Ed448 + 7 -> MLS_256_DHKEMP384_AES256GCM_SHA384_P384 + 61489 -> MLS_128_X25519KYBER768DRAFT00_AES128GCM_SHA256_ED25519 + else -> UNKNOWN(tag) + } + } +} diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt index 60bca328257..36c2ad3c70d 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/UserSessionScope.kt @@ -630,7 +630,8 @@ class UserSessionScope internal constructor( rootKeyStorePath = rootPathsProvider.rootMLSPath(userId), userId = userId, currentClientIdProvider = clientIdProvider, - passphraseStorage = globalPreferences.passphraseStorage + passphraseStorage = globalPreferences.passphraseStorage, + userConfigRepository = userConfigRepository ) } diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCase.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCase.kt index 3e2dd97ee63..9299f7a54f7 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCase.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/SyncFeatureConfigsUseCase.kt @@ -65,7 +65,7 @@ internal class SyncFeatureConfigsUseCaseImpl( // TODO handle other feature flags and after it bump version in [SlowSyncManager.CURRENT_VERSION] guestRoomConfigHandler.handle(it.guestRoomLinkModel) fileSharingConfigHandler.handle(it.fileSharingModel) - mlsConfigHandler.handle(it.mlsModel, duringSlowSync = true) + mlsConfigHandler.handle(it.mlsModel, duringSlowSync = true) it.mlsMigrationModel?.let { mlsMigrationConfigHandler.handle(it, duringSlowSync = true) } classifiedDomainsConfigHandler.handle(it.classifiedDomainsModel) conferenceCallingConfigHandler.handle(it.conferenceCallingModel) diff --git a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandler.kt b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandler.kt index 0a11676c1e7..bdf500070ac 100644 --- a/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandler.kt +++ b/logic/src/commonMain/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandler.kt @@ -36,6 +36,7 @@ class MLSConfigHandler( val isMLSSupported = mlsConfig.supportedProtocols.contains(SupportedProtocol.MLS) val previousSupportedProtocols = userConfigRepository.getSupportedProtocols().getOrElse(setOf(SupportedProtocol.PROTEUS)) val supportedProtocolsHasChanged = !previousSupportedProtocols.equals(mlsConfig.supportedProtocols) + val supportedCipherSuite = mlsConfig.supportedCipherSuite return userConfigRepository.setMLSEnabled(mlsEnabled && isMLSSupported) .flatMap { @@ -50,6 +51,10 @@ class MLSConfigHandler( } else { Either.Right(Unit) } + }.flatMap { + supportedCipherSuite?.let { + userConfigRepository.setSupportedCipherSuite(it) + } ?: Either.Right(Unit) } } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/CallRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/CallRepositoryTest.kt index da845b3807b..d1c1fa8e1b9 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/CallRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/call/CallRepositoryTest.kt @@ -47,6 +47,7 @@ import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.data.user.UserRepository import com.wire.kalium.logic.data.user.type.UserType import com.wire.kalium.logic.data.conversation.EpochChangesObserver +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.framework.TestTeam import com.wire.kalium.logic.framework.TestUser @@ -1717,7 +1718,7 @@ class CallRepositoryTest { Conversation.ProtocolInfo.MLSCapable.GroupState.ESTABLISHED, 1UL, Clock.System.now(), - Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) val qualifiedClientID = QualifiedClientID( diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapperTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapperTest.kt index 7990f4a50cd..6cca3838a42 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapperTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/conversation/ProtocolInfoMapperTest.kt @@ -19,6 +19,7 @@ package com.wire.kalium.logic.data.conversation import com.wire.kalium.logic.data.id.GroupID +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.persistence.dao.conversation.ConversationEntity import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant @@ -77,14 +78,14 @@ class ProtocolInfoMapperTest { Conversation.ProtocolInfo.MLSCapable.GroupState.ESTABLISHED, 5UL, Instant.parse("2021-03-30T15:36:00.000Z"), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) val CONVERSATION_MLS_PROTOCOL_INFO = Conversation.ProtocolInfo.MLS( GroupID("GROUP_ID"), Conversation.ProtocolInfo.MLSCapable.GroupState.ESTABLISHED, 5UL, Instant.parse("2021-03-30T15:36:00.000Z"), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) val CONVERSATION_PROTEUS_PROTOCOL_INFO = Conversation.ProtocolInfo.Proteus diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/FeatureConfigMapperTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/FeatureConfigMapperTest.kt index 8527290e603..cf0ec4b7582 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/FeatureConfigMapperTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/event/FeatureConfigMapperTest.kt @@ -157,7 +157,7 @@ class FeatureConfigMapperTest { MLSConfigDTO( SupportedProtocolDTO.MLS, listOf(SupportedProtocolDTO.MLS), - emptyList(), + listOf(1), 1 ), FeatureFlagStatusDTO.ENABLED ), diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigRepositoryTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigRepositoryTest.kt index fbb4d89532c..fb03a09ba98 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigRepositoryTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigRepositoryTest.kt @@ -74,9 +74,10 @@ class FeatureConfigRepositoryTest { ConfigsStatusModel(Status.ENABLED), ConfigsStatusModel(Status.ENABLED), MLSModel( - SupportedProtocol.PROTEUS, - setOf(SupportedProtocol.PROTEUS), - Status.ENABLED + defaultProtocol = SupportedProtocol.PROTEUS, + supportedProtocols = setOf(SupportedProtocol.PROTEUS), + status = Status.ENABLED, + supportedCipherSuite = null ), E2EIModel( E2EIConfigModel("url", 1000000L), @@ -158,8 +159,8 @@ class FeatureConfigRepositoryTest { MLSConfigDTO( SupportedProtocolDTO.PROTEUS, listOf(SupportedProtocolDTO.PROTEUS), - emptyList(), - 1 + allowedCipherSuites = listOf(1), + defaultCipherSuite = 1 ), FeatureFlagStatusDTO.ENABLED ), FeatureConfigData.E2EI( diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigTest.kt index 1d973832c20..fd3facd35fa 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/data/featureConfig/FeatureConfigTest.kt @@ -43,7 +43,12 @@ object FeatureConfigTest { secondFactorPasswordChallengeModel: ConfigsStatusModel = ConfigsStatusModel(Status.ENABLED), ssoModel: ConfigsStatusModel = ConfigsStatusModel(Status.ENABLED), validateSAMLEmailsModel: ConfigsStatusModel = ConfigsStatusModel(Status.ENABLED), - mlsModel: MLSModel = MLSModel(SupportedProtocol.PROTEUS, setOf(SupportedProtocol.PROTEUS), Status.ENABLED), + mlsModel: MLSModel = MLSModel( + defaultProtocol = SupportedProtocol.PROTEUS, + supportedProtocols = setOf(SupportedProtocol.PROTEUS), + status = Status.ENABLED, + supportedCipherSuite = null + ), e2EIModel: E2EIModel = E2EIModel(E2EIConfigModel("url", 10000L), Status.ENABLED), mlsMigrationModel: MLSMigrationModel? = MLSMigrationModel( Instant.DISTANT_FUTURE, diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt index c04faf426df..7274f7a36a9 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/client/RegisterMLSClientUseCaseTest.kt @@ -171,8 +171,8 @@ class RegisterMLSClientUseCaseTest { }.returns(result) } - fun withIsMLSClientInitialisedReturns(result: Boolean = true) = apply { - every { + suspend fun withIsMLSClientInitialisedReturns(result: Boolean = true) = apply { + coEvery { mlsClientProvider.isMLSClientInitialised() }.returns(result) } @@ -223,6 +223,5 @@ class RegisterMLSClientUseCaseTest { true, RANDOM_URL, DateTimeUtil.currentInstant() ) } - } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationUseCaseTest.kt index 223be8ea76e..d874ae67e2c 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationUseCaseTest.kt @@ -28,6 +28,7 @@ import com.wire.kalium.logic.data.conversation.MLSConversationRepository import com.wire.kalium.logic.data.conversation.mls.MLSAdditionResult import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.GroupID +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.featureFlags.FeatureSupport import com.wire.kalium.logic.framework.TestConversation @@ -331,7 +332,7 @@ class JoinExistingMLSConversationUseCaseTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 1UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("id1", "domain")) @@ -341,7 +342,7 @@ class JoinExistingMLSConversationUseCaseTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 1UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("id2", "domain")) @@ -351,7 +352,7 @@ class JoinExistingMLSConversationUseCaseTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 0UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("id3", "domain")) @@ -361,7 +362,7 @@ class JoinExistingMLSConversationUseCaseTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 0UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("self", "domain")) @@ -371,7 +372,7 @@ class JoinExistingMLSConversationUseCaseTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 0UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("one-on-one", "domain")) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationsUseCaseTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationsUseCaseTest.kt index 81661220687..a64c53ab01d 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationsUseCaseTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/JoinExistingMLSConversationsUseCaseTest.kt @@ -28,6 +28,7 @@ import com.wire.kalium.logic.data.conversation.JoinExistingMLSConversationsUseCa import com.wire.kalium.logic.data.conversation.MLSConversationRepository import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.GroupID +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.featureFlags.FeatureSupport import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.functional.Either @@ -204,7 +205,7 @@ class JoinExistingMLSConversationsUseCaseTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 1UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("id1", "domain")) @@ -214,7 +215,7 @@ class JoinExistingMLSConversationsUseCaseTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 1UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("id2", "domain")) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/RecoverMLSConversationsUseCaseTests.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/RecoverMLSConversationsUseCaseTests.kt index 750fe87df5f..cacb405ccd6 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/RecoverMLSConversationsUseCaseTests.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/conversation/RecoverMLSConversationsUseCaseTests.kt @@ -26,6 +26,7 @@ import com.wire.kalium.logic.data.conversation.JoinExistingMLSConversationUseCas import com.wire.kalium.logic.data.conversation.MLSConversationRepository import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.GroupID +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.featureFlags.FeatureSupport import com.wire.kalium.logic.framework.TestConversation import com.wire.kalium.logic.functional.Either @@ -243,7 +244,7 @@ class RecoverMLSConversationsUseCaseTests { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 1UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("id1", "domain")) @@ -253,7 +254,7 @@ class RecoverMLSConversationsUseCaseTests { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, epoch = 1UL, keyingMaterialLastUpdate = DateTimeUtil.currentInstant(), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) ).copy(id = ConversationId("id2", "domain")) } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandlerTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandlerTest.kt index b4f0ff59136..1ab4bc66274 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandlerTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/featureConfig/handler/MLSConfigHandlerTest.kt @@ -19,9 +19,12 @@ package com.wire.kalium.logic.feature.featureConfig.handler import com.wire.kalium.logic.data.featureConfig.MLSModel import com.wire.kalium.logic.data.featureConfig.Status +import com.wire.kalium.logic.data.mls.CipherSuite +import com.wire.kalium.logic.data.mls.SupportedCipherSuite import com.wire.kalium.logic.data.user.SupportedProtocol import com.wire.kalium.logic.framework.TestUser import com.wire.kalium.logic.functional.Either +import com.wire.kalium.logic.functional.right import com.wire.kalium.logic.util.arrangement.repository.UserConfigRepositoryArrangement import com.wire.kalium.logic.util.arrangement.repository.UserConfigRepositoryArrangementImpl import com.wire.kalium.logic.util.arrangement.usecase.UpdateSupportedProtocolsAndResolveOneOnOnesArrangement @@ -47,8 +50,7 @@ class MLSConfigHandlerTest { MLS_CONFIG.copy( status = Status.ENABLED, defaultProtocol = SupportedProtocol.MLS - ), - duringSlowSync = false + ), duringSlowSync = false ) coVerify { @@ -69,8 +71,7 @@ class MLSConfigHandlerTest { MLS_CONFIG.copy( status = Status.ENABLED, defaultProtocol = SupportedProtocol.PROTEUS - ), - duringSlowSync = false + ), duringSlowSync = false ) coVerify { @@ -91,8 +92,7 @@ class MLSConfigHandlerTest { MLS_CONFIG.copy( status = Status.DISABLED, defaultProtocol = SupportedProtocol.MLS - ), - duringSlowSync = false + ), duringSlowSync = false ) coVerify { @@ -114,8 +114,7 @@ class MLSConfigHandlerTest { MLS_CONFIG.copy( status = Status.ENABLED, supportedProtocols = setOf(SupportedProtocol.PROTEUS, SupportedProtocol.MLS) - ), - duringSlowSync = false + ), duringSlowSync = false ) coVerify { @@ -135,8 +134,8 @@ class MLSConfigHandlerTest { handler.handle( MLS_CONFIG.copy( status = Status.DISABLED - ), - duringSlowSync = false + + ), duringSlowSync = false ) coVerify { @@ -158,8 +157,7 @@ class MLSConfigHandlerTest { MLS_CONFIG.copy( status = Status.ENABLED, supportedProtocols = setOf(SupportedProtocol.PROTEUS, SupportedProtocol.MLS) - ), - duringSlowSync = false + ), duringSlowSync = false ) coVerify { @@ -181,8 +179,7 @@ class MLSConfigHandlerTest { MLS_CONFIG.copy( status = Status.ENABLED, supportedProtocols = setOf(SupportedProtocol.PROTEUS, SupportedProtocol.MLS) - ), - duringSlowSync = true + ), duringSlowSync = true ) coVerify { @@ -190,6 +187,47 @@ class MLSConfigHandlerTest { }.wasInvoked(exactly = once) } + + @Test + fun givenSupportedCipherSuiteIsNotNull_whenHandlling_thenStoreTheSupportedCipherSuite() = runTest { + val (arrangement, handler) = arrange { + withGetSupportedProtocolsReturning(setOf(SupportedProtocol.PROTEUS, SupportedProtocol.MLS).right()) + withSetMLSEnabledSuccessful() + withSetDefaultProtocolSuccessful() + withSetSupportedProtocolsSuccessful() + withSetSupportedCipherSuite(Unit.right()) + } + + handler.handle( + MLS_CONFIG.copy( + status = Status.ENABLED, + supportedProtocols = setOf(SupportedProtocol.PROTEUS, SupportedProtocol.MLS), + supportedCipherSuite = SupportedCipherSuite( + supported = listOf( + CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519, + CipherSuite.MLS_256_DHKEMP384_AES256GCM_SHA384_P384 + ), + default = CipherSuite.MLS_256_DHKEMP384_AES256GCM_SHA384_P384 + ) + ), + duringSlowSync = true, + ) + + coVerify { + arrangement.userConfigRepository.setSupportedCipherSuite( + eq( + SupportedCipherSuite( + supported = listOf( + CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519, + CipherSuite.MLS_256_DHKEMP384_AES256GCM_SHA384_P384 + ), + default = CipherSuite.MLS_256_DHKEMP384_AES256GCM_SHA384_P384 + ) + ) + ) + }.wasInvoked(exactly = once) + } + private class Arrangement(private val block: suspend Arrangement.() -> Unit) : UserConfigRepositoryArrangement by UserConfigRepositoryArrangementImpl(), UpdateSupportedProtocolsAndResolveOneOnOnesArrangement by UpdateSupportedProtocolsAndResolveOneOnOnesArrangementImpl() { @@ -209,8 +247,8 @@ class MLSConfigHandlerTest { val MLS_CONFIG = MLSModel( defaultProtocol = SupportedProtocol.MLS, supportedProtocols = setOf(SupportedProtocol.PROTEUS), - status = Status.ENABLED + status = Status.ENABLED, + supportedCipherSuite = null ) } - } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt index 23f16a38540..b959d300958 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/message/MessageSenderTest.kt @@ -39,6 +39,7 @@ import com.wire.kalium.logic.data.message.MessageSent import com.wire.kalium.logic.data.message.MessageTarget import com.wire.kalium.logic.data.message.RecipientEntry import com.wire.kalium.logic.data.message.SessionEstablisher +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.data.prekey.UsersWithoutSessions import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.data.user.UserRepository @@ -1271,7 +1272,7 @@ class MessageSenderTest { Conversation.ProtocolInfo.MLSCapable.GroupState.ESTABLISHED, 0UL, Instant.DISTANT_PAST, - Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) val MLS_STALE_MESSAGE_FAILURE = NetworkFailure.ServerMiscommunication( KaliumException.InvalidRequestError( diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigratorTest.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigratorTest.kt index 3fbcef10f46..d851e9e5a0a 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigratorTest.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/feature/mlsmigration/MLSMigratorTest.kt @@ -27,6 +27,7 @@ import com.wire.kalium.logic.data.conversation.mls.MLSAdditionResult import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.SelfTeamIdProvider import com.wire.kalium.logic.data.message.SystemMessageInserter +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.logic.data.user.UserRepository import com.wire.kalium.logic.framework.TestConversation @@ -306,14 +307,14 @@ class MLSMigratorTest { Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, 0UL, Instant.parse("2021-03-30T15:36:00.000Z"), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) val MLS_PROTOCOL_INFO = Conversation.ProtocolInfo.MLS( TestConversation.GROUP_ID, Conversation.ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, 0UL, Instant.parse("2021-03-30T15:36:00.000Z"), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) } } diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestConversation.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestConversation.kt index f55060e3dc4..a20e7914a45 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestConversation.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/framework/TestConversation.kt @@ -26,6 +26,7 @@ import com.wire.kalium.logic.data.conversation.MutedConversationStatus import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.GroupID import com.wire.kalium.logic.data.id.toApi +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.data.user.UserId import com.wire.kalium.network.api.base.authenticated.conversation.ConvProtocol import com.wire.kalium.network.api.base.authenticated.conversation.ConversationMemberAddedResponse @@ -343,7 +344,7 @@ object TestConversation { ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, 0UL, Instant.parse("2021-03-30T15:36:00.000Z"), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) val PROTEUS_PROTOCOL_INFO = ProtocolInfo.Proteus @@ -353,7 +354,7 @@ object TestConversation { ProtocolInfo.MLSCapable.GroupState.PENDING_JOIN, 0UL, Instant.parse("2021-03-30T15:36:00.000Z"), - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 + cipherSuite = CipherSuite.MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519 ) val CONVERSATION = Conversation( diff --git a/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt index 548592c94b0..a0e57260238 100644 --- a/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt +++ b/logic/src/commonTest/kotlin/com/wire/kalium/logic/util/arrangement/repository/UserConfigRepositoryArrangement.kt @@ -17,7 +17,6 @@ */ package com.wire.kalium.logic.util.arrangement.repository -import com.wire.kalium.logic.CoreFailure import com.wire.kalium.logic.StorageFailure import com.wire.kalium.logic.configuration.UserConfigRepository import com.wire.kalium.logic.data.featureConfig.MLSMigrationModel @@ -38,6 +37,7 @@ internal interface UserConfigRepositoryArrangement { fun withSetMLSEnabledSuccessful() suspend fun withSetMigrationConfigurationSuccessful() suspend fun withGetMigrationConfigurationReturning(result: Either) + suspend fun withSetSupportedCipherSuite(result: Either) } internal class UserConfigRepositoryArrangementImpl : UserConfigRepositoryArrangement { @@ -79,4 +79,8 @@ internal class UserConfigRepositoryArrangementImpl : UserConfigRepositoryArrange userConfigRepository.getMigrationConfiguration() }.returns(result) } + + override suspend fun withSetSupportedCipherSuite(result: Either) { + coEvery { userConfigRepository.setSupportedCipherSuite(any()) }.returns(result) + } } diff --git a/logic/src/jvmTest/kotlin/com/wire/kalium/logic/feature/scenario/OnCloseCallTest.kt b/logic/src/jvmTest/kotlin/com/wire/kalium/logic/feature/scenario/OnCloseCallTest.kt index 3638d1798f4..d0973b03091 100644 --- a/logic/src/jvmTest/kotlin/com/wire/kalium/logic/feature/scenario/OnCloseCallTest.kt +++ b/logic/src/jvmTest/kotlin/com/wire/kalium/logic/feature/scenario/OnCloseCallTest.kt @@ -27,6 +27,7 @@ import com.wire.kalium.logic.data.conversation.Conversation import com.wire.kalium.logic.data.id.ConversationId import com.wire.kalium.logic.data.id.GroupID import com.wire.kalium.logic.data.id.QualifiedIdMapperImpl +import com.wire.kalium.logic.data.mls.CipherSuite import com.wire.kalium.logic.feature.call.scenario.OnCloseCall import com.wire.kalium.logic.framework.TestUser import com.wire.kalium.network.NetworkState @@ -235,7 +236,7 @@ class OnCloseCallTest { groupState = Conversation.ProtocolInfo.MLSCapable.GroupState.ESTABLISHED, epoch = ULong.MAX_VALUE, keyingMaterialLastUpdate = Instant.DISTANT_FUTURE, - cipherSuite = Conversation.CipherSuite.MLS_128_DHKEMP256_AES128GCM_SHA256_P256 + cipherSuite = CipherSuite.MLS_128_DHKEMP256_AES128GCM_SHA256_P256 ) ) diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UserConfigDAO.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UserConfigDAO.kt index 0b9671ba6bc..ede3482c411 100644 --- a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UserConfigDAO.kt +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/dao/unread/UserConfigDAO.kt @@ -26,6 +26,7 @@ import com.wire.kalium.persistence.config.MLSMigrationEntity import com.wire.kalium.persistence.config.TeamSettingsSelfDeletionStatusEntity import com.wire.kalium.persistence.dao.MetadataDAO import com.wire.kalium.persistence.dao.SupportedProtocolEntity +import com.wire.kalium.persistence.model.SupportedCipherSuiteEntity import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.serialization.builtins.SetSerializer @@ -57,6 +58,8 @@ interface UserConfigDAO { suspend fun observeCertificateExpirationTime(url: String): Flow suspend fun setShouldNotifyForRevokedCertificate(shouldNotify: Boolean) suspend fun observeShouldNotifyForRevokedCertificate(): Flow + suspend fun setDefaultCipherSuite(cipherSuite: SupportedCipherSuiteEntity) + suspend fun getDefaultCipherSuite(): SupportedCipherSuiteEntity? } @Suppress("TooManyFunctions") @@ -176,7 +179,15 @@ internal class UserConfigDAOImpl internal constructor( override suspend fun observeShouldNotifyForRevokedCertificate(): Flow = metadataDAO.valueByKeyFlow(SHOULD_NOTIFY_FOR_REVOKED_CERTIFICATE).map { it?.toBoolean() } + override suspend fun setDefaultCipherSuite(cipherSuite: SupportedCipherSuiteEntity) { + metadataDAO.putSerializable(DEFAULT_CIPHER_SUITE_KEY, cipherSuite, SupportedCipherSuiteEntity.serializer()) + } + + override suspend fun getDefaultCipherSuite(): SupportedCipherSuiteEntity? = + metadataDAO.getSerializable(DEFAULT_CIPHER_SUITE_KEY, SupportedCipherSuiteEntity.serializer()) + private companion object { + private const val DEFAULT_CIPHER_SUITE_KEY = "DEFAULT_CIPHER_SUITE" private const val SELF_DELETING_MESSAGES_KEY = "SELF_DELETING_MESSAGES" private const val SHOULD_NOTIFY_FOR_REVOKED_CERTIFICATE = "should_notify_for_revoked_certificate" private const val MLS_MIGRATION_KEY = "MLS_MIGRATION" diff --git a/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/model/SupportedCipherSuiteEntity.kt b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/model/SupportedCipherSuiteEntity.kt new file mode 100644 index 00000000000..829c4c0b745 --- /dev/null +++ b/persistence/src/commonMain/kotlin/com/wire/kalium/persistence/model/SupportedCipherSuiteEntity.kt @@ -0,0 +1,29 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.kalium.persistence.model + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SupportedCipherSuiteEntity( + @SerialName("supported") + val supported: List, + @SerialName("default") + val default: Int +)