From 3ef78a23dbf26ebd20bf26478db209d4620b3fec Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 20 Dec 2024 19:05:29 -0500 Subject: [PATCH] feat: atr in euiccinfo activity commit 0fbec512ab7dd8be207bb771129a29eb5f9434a8 Author: septs Date: Wed Dec 18 21:27:53 2024 +0800 feat: atr in euiccinfo activity --- .../openeuicc/core/LocalProfileAssistantWrapper.kt | 2 ++ .../im/angry/openeuicc/core/OmapiApduInterface.kt | 3 +++ .../angry/openeuicc/core/usb/UsbApduInterface.kt | 9 ++++++++- .../im/angry/openeuicc/ui/EuiccInfoActivity.kt | 14 +++++++++++++- app-common/src/main/res/values/strings.xml | 3 +++ .../core/TelephonyManagerApduInterface.kt | 3 +++ .../java/net/typeblog/lpac_jni/ApduInterface.kt | 5 +++++ .../net/typeblog/lpac_jni/LocalProfileAssistant.kt | 2 ++ .../lpac_jni/impl/LocalProfileAssistantImpl.kt | 2 ++ 9 files changed, 41 insertions(+), 2 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt b/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt index b715ca0..7f35213 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/LocalProfileAssistantWrapper.kt @@ -30,6 +30,8 @@ class LocalProfileAssistantWrapper(orig: LocalProfileAssistant) : override val euiccInfo2: EuiccInfo2? get() = lpa.euiccInfo2 + override fun readATR() = lpa.readATR() + override fun setEs10xMss(mss: Byte) = lpa.setEs10xMss(mss) override fun enableProfile(iccid: String, refresh: Boolean): Boolean = diff --git a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt index 71aa386..c024b98 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/OmapiApduInterface.kt @@ -26,6 +26,9 @@ class OmapiApduInterface( override val valid: Boolean get() = service.isConnected && (this::session.isInitialized && !session.isClosed) + override fun readATR() = + session.atr?.clone() ?: throw IllegalStateException("atr unavailable") + override fun connect() { session = service.getUiccReaderCompat(port.logicalSlotIndex + 1).openSession() } diff --git a/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt b/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt index 9894343..da103e8 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/usb/UsbApduInterface.kt @@ -32,7 +32,9 @@ class UsbApduInterface( transceiver = UsbCcidTransceiver(conn, bulkIn, bulkOut, ccidDescription, verboseLoggingFlow) try { - transceiver.iccPowerOn() + // 6.1.1.1 PC_to_RDR_IccPowerOn (Page 20 of 40) + // https://www.usb.org/sites/default/files/DWG_Smart-Card_USB-ICC_ICCD_rev10.pdf + atr = transceiver.iccPowerOn().data } catch (e: Exception) { e.printStackTrace() throw e @@ -99,6 +101,11 @@ class UsbApduInterface( override val valid: Boolean get() = channelId != -1 + private var atr: ByteArray? = null + + override fun readATR() = + atr?.clone() ?: throw IllegalStateException("atr unavailable") + private fun isSuccessResponse(resp: ByteArray): Boolean = resp.size >= 2 && resp[resp.size - 2] == 0x90.toByte() && resp[resp.size - 1] == 0x00.toByte() diff --git a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt index df206c8..a36314c 100644 --- a/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt +++ b/app-common/src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt @@ -23,6 +23,7 @@ import im.angry.openeuicc.common.R import im.angry.openeuicc.core.EuiccChannel import im.angry.openeuicc.core.EuiccChannelManager import im.angry.openeuicc.util.* +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import net.typeblog.lpac_jni.impl.PKID_GSMA_LIVE_CI import net.typeblog.lpac_jni.impl.PKID_GSMA_TEST_CI @@ -41,7 +42,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { @StringRes val titleResId: Int, val content: String?, - val copiedToastResId: Int? = null + val copiedToastResId: Int? = null, ) override fun onCreate(savedInstanceState: Bundle?) { @@ -134,6 +135,17 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { } add(Item(R.string.euicc_info_ci_type, getString(resId))) } + add( + Item( + R.string.euicc_info_atr, + try { + channel.lpa.readATR().encodeHex() + } catch (e: Exception) { + getString(R.string.euicc_info_atr_unavailable) + }, + copiedToastResId = R.string.toast_atr_copied, + ) + ) } private fun formatByBoolean(b: Boolean, res: Pair): String = diff --git a/app-common/src/main/res/values/strings.xml b/app-common/src/main/res/values/strings.xml index 6da5990..4723e88 100644 --- a/app-common/src/main/res/values/strings.xml +++ b/app-common/src/main/res/values/strings.xml @@ -31,6 +31,7 @@ Confirmation string mismatch ICCID copied to clipboard EID copied to clipboard + ATR copied to clipboard Grant USB permission Permission is needed to access the USB smart card reader. @@ -132,6 +133,8 @@ GSMA Live CI GSMA Test CI Unknown eSIM CI + ATR (Answer To Reset) + ATR unavailable Yes No diff --git a/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt b/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt index 6b09368..6ab695d 100644 --- a/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt +++ b/app/src/main/java/im/angry/openeuicc/core/TelephonyManagerApduInterface.kt @@ -25,6 +25,9 @@ class TelephonyManagerApduInterface( // just that transactions might return errors or nonsense get() = lastChannel != -1 + override fun readATR() = + throw IllegalStateException("atr unavailable") + override fun connect() { // Do nothing } diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt index dfa92df..4e52a42 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/ApduInterface.kt @@ -16,4 +16,9 @@ interface ApduInterface { * callers should further check with the LPA to fully determine the validity of a channel */ val valid: Boolean + + /** + * Read Answer To Reset + */ + fun readATR(): ByteArray } \ No newline at end of file diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt index 48ab1c5..52ffce2 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/LocalProfileAssistant.kt @@ -23,6 +23,8 @@ interface LocalProfileAssistant { // Extended EuiccInfo for use with LUIs, containing information such as firmware version val euiccInfo2: EuiccInfo2? + fun readATR(): ByteArray + /** * Set the max segment size (mss) for all es10x commands. This can help with removable * eUICCs that may run at a baud rate too fast for the modem. diff --git a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt index 7310acd..bf48482 100644 --- a/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt +++ b/libs/lpac-jni/src/main/java/net/typeblog/lpac_jni/impl/LocalProfileAssistantImpl.kt @@ -188,6 +188,8 @@ class LocalProfileAssistantImpl( return ret } + override fun readATR() = apduInterface.readATR() + @Synchronized override fun enableProfile(iccid: String, refresh: Boolean): Boolean = LpacJni.es10cEnableProfile(contextHandle, iccid, refresh) == 0