From 17f56dcfcca7c35749657cd7465f1d6d517bfe85 Mon Sep 17 00:00:00 2001 From: Jov Mit Date: Thu, 5 Oct 2023 21:38:23 +0200 Subject: [PATCH] Remove PresentationSession from Holder App --- .../wallet/composables/CurveLabelFor.kt | 26 +++++++ .../selfsigned/AddSelfSignedDocumentScreen.kt | 22 +----- .../wallet/settings/SettingsFragment.kt | 1 + .../wallet/settings/SettingsScreen.kt | 76 +++++++++++++++++++ .../wallet/settings/SettingsScreenState.kt | 44 +++++++++++ .../wallet/settings/SettingsViewModel.kt | 10 +++ .../wallet/transfer/CredentialStore.kt | 23 ------ .../wallet/transfer/QrCommunicationSetup.kt | 48 ++++++------ .../transfer/ReverseQrCommunicationSetup.kt | 21 ++--- .../identity/wallet/transfer/SessionSetup.kt | 16 ---- .../wallet/transfer/TransferManager.kt | 19 ++--- .../wallet/util/NfcEngagementHandler.kt | 38 +++++----- .../identity/wallet/util/PreferencesHelper.kt | 34 +++------ 13 files changed, 232 insertions(+), 146 deletions(-) create mode 100644 appholder/src/main/java/com/android/identity/wallet/composables/CurveLabelFor.kt delete mode 100644 appholder/src/main/java/com/android/identity/wallet/transfer/CredentialStore.kt delete mode 100644 appholder/src/main/java/com/android/identity/wallet/transfer/SessionSetup.kt diff --git a/appholder/src/main/java/com/android/identity/wallet/composables/CurveLabelFor.kt b/appholder/src/main/java/com/android/identity/wallet/composables/CurveLabelFor.kt new file mode 100644 index 000000000..f69368c6b --- /dev/null +++ b/appholder/src/main/java/com/android/identity/wallet/composables/CurveLabelFor.kt @@ -0,0 +1,26 @@ +package com.android.identity.wallet.composables + +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import com.android.identity.securearea.SecureArea +import com.android.identity.wallet.R + +@Composable +fun curveLabelFor( + @SecureArea.EcCurve curveOption: Int +): String { + return when (curveOption) { + SecureArea.EC_CURVE_P256 -> stringResource(id = R.string.curve_p_256) + SecureArea.EC_CURVE_P384 -> stringResource(id = R.string.curve_p_384) + SecureArea.EC_CURVE_P521 -> stringResource(id = R.string.curve_p_521) + SecureArea.EC_CURVE_BRAINPOOLP256R1 -> stringResource(id = R.string.curve_brain_pool_p_256R1) + SecureArea.EC_CURVE_BRAINPOOLP320R1 -> stringResource(id = R.string.curve_brain_pool_p_320R1) + SecureArea.EC_CURVE_BRAINPOOLP384R1 -> stringResource(id = R.string.curve_brain_pool_p_384R1) + SecureArea.EC_CURVE_BRAINPOOLP512R1 -> stringResource(id = R.string.curve_brain_pool_p_512R1) + SecureArea.EC_CURVE_ED25519 -> stringResource(id = R.string.curve_ed25519) + SecureArea.EC_CURVE_X25519 -> stringResource(id = R.string.curve_x25519) + SecureArea.EC_CURVE_ED448 -> stringResource(id = R.string.curve_ed448) + SecureArea.EC_CURVE_X448 -> stringResource(id = R.string.curve_X448) + else -> "" + } +} \ No newline at end of file diff --git a/appholder/src/main/java/com/android/identity/wallet/selfsigned/AddSelfSignedDocumentScreen.kt b/appholder/src/main/java/com/android/identity/wallet/selfsigned/AddSelfSignedDocumentScreen.kt index 78e7cd28f..7881e6197 100644 --- a/appholder/src/main/java/com/android/identity/wallet/selfsigned/AddSelfSignedDocumentScreen.kt +++ b/appholder/src/main/java/com/android/identity/wallet/selfsigned/AddSelfSignedDocumentScreen.kt @@ -59,9 +59,9 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp -import com.android.identity.securearea.SecureArea import com.android.identity.wallet.R import com.android.identity.wallet.composables.PreviewLightDark +import com.android.identity.wallet.composables.curveLabelFor import com.android.identity.wallet.composables.gradientFor import com.android.identity.wallet.composables.keystoreNameFor import com.android.identity.wallet.document.DocumentColor @@ -991,26 +991,6 @@ private fun mdocAuthOptionLabelFor( } } -@Composable -private fun curveLabelFor( - @SecureArea.EcCurve curveOption: Int -): String { - return when (curveOption) { - SecureArea.EC_CURVE_P256 -> stringResource(id = R.string.curve_p_256) - SecureArea.EC_CURVE_P384 -> stringResource(id = R.string.curve_p_384) - SecureArea.EC_CURVE_P521 -> stringResource(id = R.string.curve_p_521) - SecureArea.EC_CURVE_BRAINPOOLP256R1 -> stringResource(id = R.string.curve_brain_pool_p_256R1) - SecureArea.EC_CURVE_BRAINPOOLP320R1 -> stringResource(id = R.string.curve_brain_pool_p_320R1) - SecureArea.EC_CURVE_BRAINPOOLP384R1 -> stringResource(id = R.string.curve_brain_pool_p_384R1) - SecureArea.EC_CURVE_BRAINPOOLP512R1 -> stringResource(id = R.string.curve_brain_pool_p_512R1) - SecureArea.EC_CURVE_ED25519 -> stringResource(id = R.string.curve_ed25519) - SecureArea.EC_CURVE_X25519 -> stringResource(id = R.string.curve_x25519) - SecureArea.EC_CURVE_ED448 -> stringResource(id = R.string.curve_ed448) - SecureArea.EC_CURVE_X448 -> stringResource(id = R.string.curve_X448) - else -> "" - } -} - @StringRes private fun documentNameFor(documentType: DocumentType): Int { return when (documentType) { diff --git a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsFragment.kt b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsFragment.kt index 17a1bb4b5..4759688b1 100644 --- a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsFragment.kt +++ b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsFragment.kt @@ -29,6 +29,7 @@ class SettingsFragment : Fragment() { modifier = Modifier.fillMaxSize(), screenState = state, onAutoCloseChanged = settingsViewModel::onConnectionAutoCloseChanged, + onEphemeralKeyCurveChanged = settingsViewModel::onEphemeralKeyCurveChanged, onUseStaticHandoverChanged = settingsViewModel::onUseStaticHandoverChanged, onUseL2CAPChanged = settingsViewModel::onL2CAPChanged, onBLEDataRetrievalModeChanged = settingsViewModel::onBleDataRetrievalChanged, diff --git a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreen.kt b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreen.kt index b4721824b..9f5b3be2a 100644 --- a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreen.kt +++ b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreen.kt @@ -1,6 +1,7 @@ package com.android.identity.wallet.settings import android.content.res.Configuration +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row @@ -9,14 +10,25 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowDropDown +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import com.android.identity.wallet.composables.curveLabelFor import com.android.identity.wallet.theme.HolderAppTheme @Composable @@ -24,6 +36,7 @@ fun SettingsScreen( modifier: Modifier = Modifier, screenState: SettingsScreenState, onAutoCloseChanged: (Boolean) -> Unit, + onEphemeralKeyCurveChanged: (newValue: SettingsScreenState.EphemeralKeyCurveOption) -> Unit, onUseStaticHandoverChanged: (Boolean) -> Unit, onUseL2CAPChanged: (Boolean) -> Unit, onBLEServiceCacheChanged: (Boolean) -> Unit, @@ -49,6 +62,11 @@ fun SettingsScreen( isChecked = screenState.autoCloseEnabled, onCheckedChange = onAutoCloseChanged ) + SettingsDropDown( + title = "Ephemeral Key Curve", + description = curveLabelFor(screenState.ephemeralKeyCurveOption.toEcCurve()), + onCurveChanged = onEphemeralKeyCurveChanged + ) SettingSectionTitle(title = "NFC Engagement") SettingToggle( title = "Use static handover", @@ -162,6 +180,63 @@ private fun SettingToggle( } } +@Composable +private fun SettingsDropDown( + modifier: Modifier = Modifier, + title: String, + description: String, + onCurveChanged: (selection: SettingsScreenState.EphemeralKeyCurveOption) -> Unit +) { + var dropDownExpanded by remember { mutableStateOf(false) } + val expandDropDown = { dropDownExpanded = true } + Row( + modifier = modifier.clickable { expandDropDown() }, + verticalAlignment = Alignment.CenterVertically + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + text = title, + style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurface + ) + Text( + text = description, + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurface + ) + } + IconButton(onClick = expandDropDown) { + Icon( + imageVector = Icons.Default.ArrowDropDown, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSurface + ) + } + val entries = SettingsScreenState.EphemeralKeyCurveOption.values().toList() + DropdownMenu( + expanded = dropDownExpanded, + onDismissRequest = { dropDownExpanded = false } + ) { + for (entry in entries) { + DropdownMenuItem( + modifier = modifier, + text = { + Text( + modifier = Modifier.fillMaxWidth(), + text = curveLabelFor(curveOption = entry.toEcCurve()) + ) + }, + onClick = { + onCurveChanged(entry) + dropDownExpanded = false + } + ) + } + } + } +} + + @Preview(showBackground = true) @Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable @@ -171,6 +246,7 @@ private fun SettingsScreenPreview() { modifier = Modifier.fillMaxSize(), screenState = SettingsScreenState(), onAutoCloseChanged = {}, + onEphemeralKeyCurveChanged = {}, onUseStaticHandoverChanged = {}, onUseL2CAPChanged = {}, onBLEServiceCacheChanged = {}, diff --git a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreenState.kt b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreenState.kt index f907e53ec..82fb2be11 100644 --- a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreenState.kt +++ b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsScreenState.kt @@ -1,12 +1,17 @@ package com.android.identity.wallet.settings +import android.os.Parcelable import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable +import com.android.identity.securearea.SecureArea +import com.android.identity.securearea.SecureArea.EcCurve +import kotlinx.parcelize.Parcelize @Stable @Immutable data class SettingsScreenState( val autoCloseEnabled: Boolean = true, + val ephemeralKeyCurveOption: EphemeralKeyCurveOption = EphemeralKeyCurveOption.P256, val useStaticHandover: Boolean = true, val isL2CAPEnabled: Boolean = false, val isBleClearCacheEnabled: Boolean = false, @@ -48,4 +53,43 @@ data class SettingsScreenState( || wifiAwareEnabled || nfcEnabled } + + @Parcelize + enum class EphemeralKeyCurveOption : Parcelable { + P256, + P384, + P521, + BrainPoolP256R1, + BrainPoolP320R1, + BrainPoolP384R1, + BrainPoolP512R1; + + fun toEcCurve(): Int { + + return when (this) { + P256 -> SecureArea.EC_CURVE_P256 + P384 -> SecureArea.EC_CURVE_P384 + P521 -> SecureArea.EC_CURVE_P521 + BrainPoolP256R1 -> SecureArea.EC_CURVE_BRAINPOOLP256R1 + BrainPoolP320R1 -> SecureArea.EC_CURVE_BRAINPOOLP320R1 + BrainPoolP384R1 -> SecureArea.EC_CURVE_BRAINPOOLP384R1 + BrainPoolP512R1 -> SecureArea.EC_CURVE_BRAINPOOLP512R1 + } + } + + companion object { + fun fromEcCurve(@EcCurve curve: Int): EphemeralKeyCurveOption { + return when (curve) { + SecureArea.EC_CURVE_P256 -> P256 + SecureArea.EC_CURVE_P384 -> P384 + SecureArea.EC_CURVE_P521 -> P521 + SecureArea.EC_CURVE_BRAINPOOLP256R1 -> BrainPoolP256R1 + SecureArea.EC_CURVE_BRAINPOOLP320R1 -> BrainPoolP320R1 + SecureArea.EC_CURVE_BRAINPOOLP384R1 -> BrainPoolP384R1 + SecureArea.EC_CURVE_BRAINPOOLP512R1 -> BrainPoolP512R1 + else -> throw IllegalStateException("Unknown EcCurve") + } + } + } + } } \ No newline at end of file diff --git a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsViewModel.kt b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsViewModel.kt index aaa035af1..ae1562667 100644 --- a/appholder/src/main/java/com/android/identity/wallet/settings/SettingsViewModel.kt +++ b/appholder/src/main/java/com/android/identity/wallet/settings/SettingsViewModel.kt @@ -14,6 +14,9 @@ class SettingsViewModel : ViewModel() { fun loadSettings() { val settingsState = SettingsScreenState( autoCloseEnabled = PreferencesHelper.isConnectionAutoCloseEnabled(), + ephemeralKeyCurveOption = SettingsScreenState.EphemeralKeyCurveOption.fromEcCurve( + PreferencesHelper.getEphemeralKeyCurveOption() + ), useStaticHandover = PreferencesHelper.shouldUseStaticHandover(), isL2CAPEnabled = PreferencesHelper.isBleL2capEnabled(), isBleClearCacheEnabled = PreferencesHelper.isBleClearCacheEnabled(), @@ -31,6 +34,13 @@ class SettingsViewModel : ViewModel() { mutableSettingsState.update { it.copy(autoCloseEnabled = newValue) } } + fun onEphemeralKeyCurveChanged( + ephemeralKeyCurveOption: SettingsScreenState.EphemeralKeyCurveOption + ) { + PreferencesHelper.setEphemeralKeyCurveOption(ephemeralKeyCurveOption.toEcCurve()) + mutableSettingsState.update { it.copy(ephemeralKeyCurveOption = ephemeralKeyCurveOption) } + } + fun onUseStaticHandoverChanged(newValue: Boolean) { PreferencesHelper.setUseStaticHandover(newValue) mutableSettingsState.update { it.copy(useStaticHandover = newValue) } diff --git a/appholder/src/main/java/com/android/identity/wallet/transfer/CredentialStore.kt b/appholder/src/main/java/com/android/identity/wallet/transfer/CredentialStore.kt deleted file mode 100644 index 79b6e35c9..000000000 --- a/appholder/src/main/java/com/android/identity/wallet/transfer/CredentialStore.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.android.identity.wallet.transfer - -import android.content.Context -import com.android.identity.android.legacy.IdentityCredentialStore -import com.android.identity.wallet.util.PreferencesHelper - -class CredentialStore( - private val context: Context -) { - - fun createIdentityCredentialStore(): IdentityCredentialStore { - return if (PreferencesHelper.isHardwareBacked()) - IdentityCredentialStore.getHardwareInstance(context) - ?: createKeystoreBackedStore() else createKeystoreBackedStore() - } - - private fun createKeystoreBackedStore(): IdentityCredentialStore { - val keystoreBackedStorageLocation = PreferencesHelper - .getKeystoreBackedStorageLocation(context) - return IdentityCredentialStore - .getKeystoreInstance(context, keystoreBackedStorageLocation) - } -} \ No newline at end of file diff --git a/appholder/src/main/java/com/android/identity/wallet/transfer/QrCommunicationSetup.kt b/appholder/src/main/java/com/android/identity/wallet/transfer/QrCommunicationSetup.kt index 4f7d67b4d..aef2c34b3 100644 --- a/appholder/src/main/java/com/android/identity/wallet/transfer/QrCommunicationSetup.kt +++ b/appholder/src/main/java/com/android/identity/wallet/transfer/QrCommunicationSetup.kt @@ -1,27 +1,36 @@ package com.android.identity.wallet.transfer import android.content.Context -import com.android.identity.android.mdoc.transport.DataTransport import com.android.identity.android.mdoc.deviceretrieval.DeviceRetrievalHelper -import com.android.identity.android.legacy.PresentationSession import com.android.identity.android.mdoc.engagement.QrEngagementHelper +import com.android.identity.android.mdoc.transport.DataTransport +import com.android.identity.internal.Util +import com.android.identity.securearea.SecureArea +import com.android.identity.wallet.util.PreferencesHelper import com.android.identity.wallet.util.log import com.android.identity.wallet.util.mainExecutor +import java.security.KeyPair import java.security.PublicKey class QrCommunicationSetup( private val context: Context, private val onConnecting: () -> Unit, private val onQrEngagementReady: () -> Unit, - private val onDeviceRetrievalHelperReady: (session: PresentationSession, deviceRetrievalHelper: DeviceRetrievalHelper) -> Unit, + private val onDeviceRetrievalHelperReady: (deviceRetrievalHelper: DeviceRetrievalHelper) -> Unit, private val onNewDeviceRequest: (request: ByteArray) -> Unit, - private val onSendResponseApdu: (responseApdu: ByteArray) -> Unit, private val onDisconnected: (transportSpecificTermination: Boolean) -> Unit, private val onCommunicationError: (error: Throwable) -> Unit, ) { - private val session = SessionSetup(CredentialStore(context)).createSession() + private val settings = PreferencesHelper.apply { initialize(context) } private val connectionSetup = ConnectionSetup(context) + private val eDeviceKeyPair = Util.createEphemeralKeyPair(settings.getEphemeralKeyCurveOption()) + + private var deviceRetrievalHelper: DeviceRetrievalHelper? = null + private lateinit var qrEngagement: QrEngagementHelper + + val deviceEngagementUriEncoded: String + get() = qrEngagement.deviceEngagementUriEncoded private val qrEngagementListener = object : QrEngagementHelper.Listener { @@ -45,7 +54,7 @@ class QrCommunicationSetup( context, deviceRetrievalHelperListener, context.mainExecutor(), - session.ephemeralKeyPair + eDeviceKeyPair ) builder.useForwardEngagement( transport, @@ -54,7 +63,7 @@ class QrCommunicationSetup( ) deviceRetrievalHelper = builder.build() qrEngagement.close() - onDeviceRetrievalHelperReady(session, deviceRetrievalHelper!!) + onDeviceRetrievalHelperReady(requireNotNull(deviceRetrievalHelper)) } override fun onError(error: Throwable) { @@ -66,8 +75,6 @@ class QrCommunicationSetup( private val deviceRetrievalHelperListener = object : DeviceRetrievalHelper.Listener { override fun onEReaderKeyReceived(eReaderKey: PublicKey) { log("DeviceRetrievalHelper Listener (QR): OnEReaderKeyReceived") - session.setSessionTranscript(deviceRetrievalHelper!!.sessionTranscript) - session.setReaderEphemeralPublicKey(eReaderKey) } override fun onDeviceRequest(deviceRequestBytes: ByteArray) { @@ -86,22 +93,15 @@ class QrCommunicationSetup( } } - private lateinit var qrEngagement: QrEngagementHelper - private var deviceRetrievalHelper: DeviceRetrievalHelper? = null - - val deviceEngagementUriEncoded: String - get() = qrEngagement.deviceEngagementUriEncoded - fun configure() { - qrEngagement = - QrEngagementHelper.Builder( - context, - session.ephemeralKeyPair.public, - connectionSetup.getConnectionOptions(), - qrEngagementListener, - context.mainExecutor()) - .setConnectionMethods(connectionSetup.getConnectionMethods()) - .build() + qrEngagement = QrEngagementHelper.Builder( + context, + eDeviceKeyPair.public, + connectionSetup.getConnectionOptions(), + qrEngagementListener, + context.mainExecutor() + ).setConnectionMethods(connectionSetup.getConnectionMethods()) + .build() } fun close() { diff --git a/appholder/src/main/java/com/android/identity/wallet/transfer/ReverseQrCommunicationSetup.kt b/appholder/src/main/java/com/android/identity/wallet/transfer/ReverseQrCommunicationSetup.kt index edf721866..98244e280 100644 --- a/appholder/src/main/java/com/android/identity/wallet/transfer/ReverseQrCommunicationSetup.kt +++ b/appholder/src/main/java/com/android/identity/wallet/transfer/ReverseQrCommunicationSetup.kt @@ -3,30 +3,33 @@ package com.android.identity.wallet.transfer import android.content.Context import android.net.Uri import android.util.Base64 +import com.android.identity.android.mdoc.deviceretrieval.DeviceRetrievalHelper import com.android.identity.android.mdoc.transport.DataTransport +import com.android.identity.internal.Util import com.android.identity.mdoc.engagement.EngagementParser import com.android.identity.mdoc.origininfo.OriginInfo -import com.android.identity.android.mdoc.deviceretrieval.DeviceRetrievalHelper -import com.android.identity.android.legacy.PresentationSession +import com.android.identity.wallet.util.PreferencesHelper import com.android.identity.wallet.util.log import com.android.identity.wallet.util.mainExecutor import java.security.PublicKey class ReverseQrCommunicationSetup( private val context: Context, - private val onPresentationReady: (session: PresentationSession, presentation: DeviceRetrievalHelper) -> Unit, + private val onPresentationReady: (presentation: DeviceRetrievalHelper) -> Unit, private val onNewRequest: (request: ByteArray) -> Unit, private val onDisconnected: () -> Unit, private val onCommunicationError: (error: Throwable) -> Unit, ) { - private val session = SessionSetup(CredentialStore(context)).createSession() + private val settings = PreferencesHelper.apply { initialize(context) } private val connectionSetup = ConnectionSetup(context) + private val eDeviceKeyPair = Util.createEphemeralKeyPair(settings.getEphemeralKeyCurveOption()) + + private var presentation: DeviceRetrievalHelper? = null + private val presentationListener = object : DeviceRetrievalHelper.Listener { override fun onEReaderKeyReceived(eReaderKey: PublicKey) { log("DeviceRetrievalHelper Listener (QR): OnEReaderKeyReceived") - session.setSessionTranscript(presentation!!.sessionTranscript) - session.setReaderEphemeralPublicKey(eReaderKey) } override fun onDeviceRequest(deviceRequestBytes: ByteArray) { @@ -42,8 +45,6 @@ class ReverseQrCommunicationSetup( } } - private var presentation: DeviceRetrievalHelper? = null - fun configure( reverseEngagementUri: String, origins: List @@ -78,10 +79,10 @@ class ReverseQrCommunicationSetup( context, presentationListener, context.mainExecutor(), - session.ephemeralKeyPair + eDeviceKeyPair ) builder.useReverseEngagement(transport, encodedReaderEngagement, origins) presentation = builder.build() - onPresentationReady(session, presentation!!) + onPresentationReady(requireNotNull(presentation)) } } \ No newline at end of file diff --git a/appholder/src/main/java/com/android/identity/wallet/transfer/SessionSetup.kt b/appholder/src/main/java/com/android/identity/wallet/transfer/SessionSetup.kt deleted file mode 100644 index e69f0d5c5..000000000 --- a/appholder/src/main/java/com/android/identity/wallet/transfer/SessionSetup.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.android.identity.wallet.transfer - -import com.android.identity.android.legacy.IdentityCredentialStore.CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 -import com.android.identity.android.legacy.PresentationSession - -class SessionSetup( - private val credentialStore: CredentialStore -) { - - fun createSession(): PresentationSession { - val store = credentialStore.createIdentityCredentialStore() - return store.createPresentationSession( - CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 - ) - } -} \ No newline at end of file diff --git a/appholder/src/main/java/com/android/identity/wallet/transfer/TransferManager.kt b/appholder/src/main/java/com/android/identity/wallet/transfer/TransferManager.kt index 6d765a801..40f6195f1 100644 --- a/appholder/src/main/java/com/android/identity/wallet/transfer/TransferManager.kt +++ b/appholder/src/main/java/com/android/identity/wallet/transfer/TransferManager.kt @@ -51,14 +51,13 @@ class TransferManager private constructor(private val context: Context) { private var reversedQrCommunicationSetup: ReverseQrCommunicationSetup? = null private var qrCommunicationSetup: QrCommunicationSetup? = null - private var hostApduService: HostApduService? = null private var hasStarted = false private lateinit var communication: Communication private var transferStatusLd = MutableLiveData() - fun setCommunication(session: PresentationSession, communication: Communication) { + fun setCommunication(communication: Communication) { this.communication = communication } @@ -82,7 +81,7 @@ class TransferManager private constructor(private val context: Context) { communication = Communication.getInstance(context) reversedQrCommunicationSetup = ReverseQrCommunicationSetup( context = context, - onPresentationReady = { session, presentation -> + onPresentationReady = { presentation -> communication.setupPresentation(presentation) }, onNewRequest = { request -> @@ -109,7 +108,7 @@ class TransferManager private constructor(private val context: Context) { context = context, onConnecting = { transferStatusLd.value = TransferStatus.CONNECTING }, onQrEngagementReady = { transferStatusLd.value = TransferStatus.QR_ENGAGEMENT_READY }, - onDeviceRetrievalHelperReady = { session, deviceRetrievalHelper -> + onDeviceRetrievalHelperReady = { deviceRetrievalHelper -> communication.setupPresentation(deviceRetrievalHelper) transferStatusLd.value = TransferStatus.CONNECTED }, @@ -117,13 +116,11 @@ class TransferManager private constructor(private val context: Context) { communication.setDeviceRequest(deviceRequest) transferStatusLd.value = TransferStatus.REQUEST }, - onSendResponseApdu = { responseApdu -> hostApduService?.sendResponseApdu(responseApdu) }, - onDisconnected = { transferStatusLd.value = TransferStatus.DISCONNECTED }, - onCommunicationError = { error -> - log("onError: ${error.message}") - transferStatusLd.value = TransferStatus.ERROR - } - ).apply { + onDisconnected = { transferStatusLd.value = TransferStatus.DISCONNECTED } + ) { error -> + log("onError: ${error.message}") + transferStatusLd.value = TransferStatus.ERROR + }.apply { configure() } hasStarted = true diff --git a/appholder/src/main/java/com/android/identity/wallet/util/NfcEngagementHandler.kt b/appholder/src/main/java/com/android/identity/wallet/util/NfcEngagementHandler.kt index cb43af8b2..1f2a01fe9 100644 --- a/appholder/src/main/java/com/android/identity/wallet/util/NfcEngagementHandler.kt +++ b/appholder/src/main/java/com/android/identity/wallet/util/NfcEngagementHandler.kt @@ -22,28 +22,30 @@ import android.os.Bundle import android.os.Handler import android.os.Looper import androidx.navigation.NavDeepLinkBuilder -import com.android.identity.android.mdoc.transport.DataTransport -import com.android.identity.android.mdoc.engagement.NfcEngagementHelper import com.android.identity.android.mdoc.deviceretrieval.DeviceRetrievalHelper -import com.android.identity.android.legacy.PresentationSession -import com.android.identity.wallet.MainActivity +import com.android.identity.android.mdoc.engagement.NfcEngagementHelper +import com.android.identity.android.mdoc.transport.DataTransport +import com.android.identity.internal.Util import com.android.identity.wallet.R import com.android.identity.wallet.transfer.Communication import com.android.identity.wallet.transfer.ConnectionSetup -import com.android.identity.wallet.transfer.CredentialStore -import com.android.identity.wallet.transfer.SessionSetup import com.android.identity.wallet.transfer.TransferManager import java.security.PublicKey - class NfcEngagementHandler : HostApduService() { private lateinit var engagementHelper: NfcEngagementHelper - private lateinit var session: PresentationSession private lateinit var communication: Communication private lateinit var transferManager: TransferManager + private var presentation: DeviceRetrievalHelper? = null + private val settings by lazy { + PreferencesHelper.apply { initialize(applicationContext) } + } + private val eDeviceKeyPair by lazy { + Util.createEphemeralKeyPair(settings.getEphemeralKeyCurveOption()) + } private val nfcEngagementListener = object : NfcEngagementHelper.Listener { override fun onTwoWayEngagementDetected() { @@ -52,7 +54,8 @@ class NfcEngagementHandler : HostApduService() { override fun onDeviceConnecting() { log("Engagement Listener: Device Connecting. Launching Transfer Screen") - val launchAppIntent = Intent(applicationContext, com.android.identity.wallet.MainActivity::class.java) + val launchAppIntent = + Intent(applicationContext, com.android.identity.wallet.MainActivity::class.java) launchAppIntent.action = Intent.ACTION_VIEW launchAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) launchAppIntent.addCategory(Intent.CATEGORY_DEFAULT) @@ -75,11 +78,12 @@ class NfcEngagementHandler : HostApduService() { } log("Engagement Listener: Device Connected via NFC") + val builder = DeviceRetrievalHelper.Builder( applicationContext, presentationListener, applicationContext.mainExecutor(), - session.ephemeralKeyPair + eDeviceKeyPair ) builder.useForwardEngagement( transport, @@ -100,10 +104,9 @@ class NfcEngagementHandler : HostApduService() { } private val presentationListener = object : DeviceRetrievalHelper.Listener { + override fun onEReaderKeyReceived(eReaderKey: PublicKey) { log("DeviceRetrievalHelper Listener (NFC): OnEReaderKeyReceived") - session.setSessionTranscript(presentation!!.sessionTranscript) - session.setReaderEphemeralPublicKey(eReaderKey) } override fun onDeviceRequest(deviceRequestBytes: ByteArray) { @@ -126,17 +129,17 @@ class NfcEngagementHandler : HostApduService() { override fun onCreate() { super.onCreate() log("onCreate") - session = SessionSetup(CredentialStore(applicationContext)).createSession() communication = Communication.getInstance(applicationContext) transferManager = TransferManager.getInstance(applicationContext) - transferManager.setCommunication(session, communication) + transferManager.setCommunication(communication) val connectionSetup = ConnectionSetup(applicationContext) val builder = NfcEngagementHelper.Builder( applicationContext, - session.ephemeralKeyPair.public, + eDeviceKeyPair.public, connectionSetup.getConnectionOptions(), nfcEngagementListener, - applicationContext.mainExecutor()) + applicationContext.mainExecutor() + ) if (PreferencesHelper.shouldUseStaticHandover()) { builder.useStaticHandover(connectionSetup.getConnectionMethods()) } else { @@ -171,6 +174,7 @@ class NfcEngagementHandler : HostApduService() { logWarning("reader didn't connect inside $timeoutSeconds seconds, closing") engagementHelper.close() } - }, timeoutSeconds*1000L) + }, timeoutSeconds * 1000L) } } + diff --git a/appholder/src/main/java/com/android/identity/wallet/util/PreferencesHelper.kt b/appholder/src/main/java/com/android/identity/wallet/util/PreferencesHelper.kt index 30512ea00..f8323196f 100644 --- a/appholder/src/main/java/com/android/identity/wallet/util/PreferencesHelper.kt +++ b/appholder/src/main/java/com/android/identity/wallet/util/PreferencesHelper.kt @@ -4,10 +4,11 @@ import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit import androidx.preference.PreferenceManager +import com.android.identity.securearea.SecureArea +import com.android.identity.securearea.SecureArea.EcCurve import java.io.File object PreferencesHelper { - private const val HARDWARE_BACKED_PREFERENCE = "com.android.mdl.app.HARDWARE_BACKED" private const val BLE_DATA_RETRIEVAL = "ble_transport" private const val BLE_DATA_RETRIEVAL_PERIPHERAL_MODE = "ble_transport_peripheral_mode" private const val BLE_DATA_L2CAP = "ble_l2cap" @@ -17,30 +18,12 @@ object PreferencesHelper { private const val DEBUG_LOG = "debug_log" private const val CONNECTION_AUTO_CLOSE = "connection_auto_close" private const val STATIC_HANDOVER = "static_handover" -// const val USE_READER_AUTH = "use_reader_authentication" + private const val EPHEMERAL_KEY_CURVE_OPTION = "ephemeral_key_curve" private lateinit var sharedPreferences: SharedPreferences fun initialize(context: Context) { sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - setHardwareBacked(false) - } - - fun setHardwareBacked(isHardwareBacked: Boolean) { - sharedPreferences.edit { - putBoolean(HARDWARE_BACKED_PREFERENCE, isHardwareBacked) - } - } - - fun hasHardwareBackedPreference(): Boolean { - return sharedPreferences.contains(HARDWARE_BACKED_PREFERENCE) - } - - fun isHardwareBacked(): Boolean { - if (!hasHardwareBackedPreference()) { - throw IllegalStateException("No preference set for used implementation.") - } - return sharedPreferences.getBoolean(HARDWARE_BACKED_PREFERENCE, false) } fun getKeystoreBackedStorageLocation(context: Context): File { @@ -122,9 +105,12 @@ object PreferencesHelper { sharedPreferences.edit { putBoolean(DEBUG_LOG, enabled) } } - fun isReaderAuthenticationEnabled(context: Context): Boolean { - // return sharedPreferences.getBoolean(USE_READER_AUTH, false) - // Just returning false now as we are not using ACP to control the reader authentication - return false + @EcCurve + fun getEphemeralKeyCurveOption(): Int { + return sharedPreferences.getInt(EPHEMERAL_KEY_CURVE_OPTION, SecureArea.EC_CURVE_P256) + } + + fun setEphemeralKeyCurveOption(@EcCurve newValue: Int) { + sharedPreferences.edit { putInt(EPHEMERAL_KEY_CURVE_OPTION, newValue) } } } \ No newline at end of file