From 6c9b16088fbd2066d54d69b7ddcc7ce9fc9a99e3 Mon Sep 17 00:00:00 2001 From: Valere Date: Tue, 2 Feb 2021 08:59:28 +0100 Subject: [PATCH] Secure secrets passed to intent --- .../im/vector/app/features/auth/ReAuthActivity.kt | 14 ++++++++++---- .../im/vector/app/features/auth/ReAuthEvents.kt | 2 +- .../im/vector/app/features/auth/ReAuthState.kt | 6 ++++-- .../im/vector/app/features/auth/ReAuthViewModel.kt | 13 +++++++++---- .../crypto/recover/BootstrapSharedViewModel.kt | 5 ++++- .../crosssigning/CrossSigningSettingsViewModel.kt | 5 ++++- .../features/settings/devices/DevicesViewModel.kt | 5 ++++- 7 files changed, 36 insertions(+), 14 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt index cd7a32275d..a95c2b73cc 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthActivity.kt @@ -49,7 +49,8 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory { val flowType: String?, val title: String?, val session: String?, - val lastErrorCode: String? + val lastErrorCode: String?, + val resultKeyStoreAlias: String ) : Parcelable // For sso @@ -101,7 +102,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory { is ReAuthEvents.PasswordFinishSuccess -> { setResult(RESULT_OK, Intent().apply { putExtra(RESULT_FLOW_TYPE, LoginFlowTypes.PASSWORD) - putExtra(RESULT_VALUE, it.password) + putExtra(RESULT_VALUE, it.passwordSafeForIntent) }) finish() } @@ -197,8 +198,13 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory { const val EXTRA_REASON_TITLE = "EXTRA_REASON_TITLE" const val RESULT_FLOW_TYPE = "RESULT_FLOW_TYPE" const val RESULT_VALUE = "RESULT_VALUE" + const val DEFAULT_RESULT_KEYSTORE_ALIAS = "ReAuthActivity" - fun newIntent(context: Context, fromError: RegistrationFlowResponse, lastErrorCode: String?, reasonTitle: String?): Intent { + fun newIntent(context: Context, + fromError: RegistrationFlowResponse, + lastErrorCode: String?, + reasonTitle: String?, + resultKeyStoreAlias: String = DEFAULT_RESULT_KEYSTORE_ALIAS): Intent { val authType = when (fromError.nextUncompletedStage()) { LoginFlowTypes.PASSWORD -> { LoginFlowTypes.PASSWORD @@ -212,7 +218,7 @@ class ReAuthActivity : SimpleFragmentActivity(), ReAuthViewModel.Factory { } } return Intent(context, ReAuthActivity::class.java).apply { - putExtra(MvRx.KEY_ARG, Args(authType, reasonTitle, fromError.session, lastErrorCode)) + putExtra(MvRx.KEY_ARG, Args(authType, reasonTitle, fromError.session, lastErrorCode, resultKeyStoreAlias)) } } } diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthEvents.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthEvents.kt index 303d87a4c7..8cf9be6fb1 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthEvents.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthEvents.kt @@ -21,5 +21,5 @@ import im.vector.app.core.platform.VectorViewEvents sealed class ReAuthEvents : VectorViewEvents { data class OpenSsoURl(val url: String) : ReAuthEvents() object Dismiss : ReAuthEvents() - data class PasswordFinishSuccess(val password: String) : ReAuthEvents() + data class PasswordFinishSuccess(val passwordSafeForIntent: String) : ReAuthEvents() } diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt index 633743dbcb..540a08405c 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthState.kt @@ -24,13 +24,15 @@ data class ReAuthState( val flowType: String? = null, val ssoFallbackPageWasShown: Boolean = false, val passwordVisible: Boolean = false, - val lastErrorCode: String? = null + val lastErrorCode: String? = null, + val resultKeyStoreAlias: String = "" ) : MvRxState { constructor(args: ReAuthActivity.Args) : this( args.title, args.session, args.flowType, - lastErrorCode = args.lastErrorCode + lastErrorCode = args.lastErrorCode, + resultKeyStoreAlias = args.resultKeyStoreAlias ) constructor() : this(null, null) diff --git a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt index d29bf2828d..4b477990c0 100644 --- a/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/auth/ReAuthViewModel.kt @@ -24,14 +24,14 @@ import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.platform.VectorViewModel -import org.matrix.android.sdk.api.auth.AuthenticationService import org.matrix.android.sdk.api.auth.data.LoginFlowTypes import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.internal.crypto.crosssigning.toBase64NoPadding +import java.io.ByteArrayOutputStream class ReAuthViewModel @AssistedInject constructor( @Assisted val initialState: ReAuthState, - private val session: Session, - private val authenticationService: AuthenticationService + private val session: Session ) : VectorViewModel(initialState) { @AssistedFactory @@ -72,7 +72,12 @@ class ReAuthViewModel @AssistedInject constructor( } } is ReAuthActions.ReAuthWithPass -> { - _viewEvents.post(ReAuthEvents.PasswordFinishSuccess(action.password)) + val safeForIntentCypher = ByteArrayOutputStream().also { + it.use { + session.securelyStoreObject(action.password, initialState.resultKeyStoreAlias, it) + } + }.toByteArray().toBase64NoPadding() + _viewEvents.post(ReAuthEvents.PasswordFinishSuccess(safeForIntentCypher)) } } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt index d67c9afd42..9282dc3e3e 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt @@ -34,6 +34,7 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.resources.StringProvider +import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -44,6 +45,7 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage +import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.keysbackup.model.rest.KeysVersionResult import org.matrix.android.sdk.internal.crypto.keysbackup.util.extractCurveKeyFromRecoveryKey import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth @@ -269,10 +271,11 @@ class BootstrapSharedViewModel @AssistedInject constructor( uiaContinuation?.resume(DefaultBaseAuth(session = pendingAuth?.session ?: "")) } is BootstrapActions.PasswordAuthDone -> { + val decryptedPass = session.loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) uiaContinuation?.resume( UserPasswordAuth( session = pendingAuth?.session, - password = action.password, + password = decryptedPass, user = session.myUserId ) ) diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index 9a1150046d..d29ecefff1 100644 --- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -26,6 +26,7 @@ import im.vector.app.R import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider +import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper import io.reactivex.Observable import io.reactivex.functions.BiFunction @@ -38,6 +39,7 @@ import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage +import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.crosssigning.isVerified import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo @@ -134,10 +136,11 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( Unit } is CrossSigningSettingsAction.PasswordAuthDone -> { + val decryptedPass = session.loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) uiaContinuation?.resume( UserPasswordAuth( session = pendingAuth?.session, - password = action.password, + password = decryptedPass, user = session.myUserId ) ) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index db29ced873..610c89706e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -32,6 +32,7 @@ import dagger.assisted.AssistedInject import im.vector.app.R import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider +import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper import io.reactivex.Observable import io.reactivex.functions.BiFunction @@ -51,6 +52,7 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxStat import org.matrix.android.sdk.internal.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.internal.auth.registration.nextUncompletedStage import org.matrix.android.sdk.internal.crypto.crosssigning.DeviceTrustLevel +import org.matrix.android.sdk.internal.crypto.crosssigning.fromBase64 import org.matrix.android.sdk.internal.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.internal.crypto.model.rest.DefaultBaseAuth import org.matrix.android.sdk.internal.crypto.model.rest.DeviceInfo @@ -221,10 +223,11 @@ class DevicesViewModel @AssistedInject constructor( Unit } is DevicesAction.PasswordAuthDone -> { + val decryptedPass = session.loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) uiaContinuation?.resume( UserPasswordAuth( session = pendingAuth?.session, - password = action.password, + password = decryptedPass, user = session.myUserId ) )