diff --git a/app-common/src/main/java/im/angry/openeuicc/core/ApduInterfaceAtrProvider.kt b/app-common/src/main/java/im/angry/openeuicc/core/ApduInterfaceAtrProvider.kt new file mode 100644 index 0000000..c3646d2 --- /dev/null +++ b/app-common/src/main/java/im/angry/openeuicc/core/ApduInterfaceAtrProvider.kt @@ -0,0 +1,5 @@ +package im.angry.openeuicc.core + +interface ApduInterfaceAtrProvider { + val atr: ByteArray? +} \ No newline at end of file diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt index 541f867..5f399ea 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannel.kt @@ -16,6 +16,11 @@ interface EuiccChannel { val valid: Boolean + /** + * Answer to Reset (ATR) value of the underlying interface, if any + */ + val atr: ByteArray? + /** * Intrinsic name of this channel. For device-internal SIM slots, * this should be null; for USB readers, this should be the name of diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt index a281948..a82cb97 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelImpl.kt @@ -11,7 +11,7 @@ class EuiccChannelImpl( override val type: String, override val port: UiccPortInfoCompat, override val intrinsicChannelName: String?, - apduInterface: ApduInterface, + private val apduInterface: ApduInterface, verboseLoggingFlow: Flow, ignoreTLSCertificateFlow: Flow ) : EuiccChannel { @@ -22,6 +22,9 @@ class EuiccChannelImpl( override val lpa: LocalProfileAssistant = LocalProfileAssistantImpl(apduInterface, HttpInterfaceImpl(verboseLoggingFlow, ignoreTLSCertificateFlow)) + override val atr: ByteArray? + get() = (apduInterface as? ApduInterfaceAtrProvider)?.atr + override val valid: Boolean get() = lpa.valid diff --git a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt index 6011f53..4204e82 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/EuiccChannelWrapper.kt @@ -33,6 +33,8 @@ class EuiccChannelWrapper(orig: EuiccChannel) : EuiccChannel { get() = channel.valid override val intrinsicChannelName: String? get() = channel.intrinsicChannelName + override val atr: ByteArray? + get() = channel.atr override fun close() = channel.close() 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..c70669d 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 @@ -15,7 +15,7 @@ class OmapiApduInterface( private val service: SEService, private val port: UiccPortInfoCompat, private val verboseLoggingFlow: Flow -): ApduInterface { +): ApduInterface, ApduInterfaceAtrProvider { companion object { const val TAG = "OmapiApduInterface" } @@ -26,6 +26,9 @@ class OmapiApduInterface( override val valid: Boolean get() = service.isConnected && (this::session.isInitialized && !session.isClosed) + override val atr: ByteArray? + get() = session.atr + 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..624ef89 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 @@ -3,6 +3,7 @@ package im.angry.openeuicc.core.usb import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbEndpoint import android.util.Log +import im.angry.openeuicc.core.ApduInterfaceAtrProvider import im.angry.openeuicc.util.* import kotlinx.coroutines.flow.Flow import net.typeblog.lpac_jni.ApduInterface @@ -12,7 +13,7 @@ class UsbApduInterface( private val bulkIn: UsbEndpoint, private val bulkOut: UsbEndpoint, private val verboseLoggingFlow: Flow -): ApduInterface { +) : ApduInterface, ApduInterfaceAtrProvider { companion object { private const val TAG = "UsbApduInterface" } @@ -22,6 +23,8 @@ class UsbApduInterface( private var channelId = -1 + override var atr: ByteArray? = null + override fun connect() { ccidDescription = UsbCcidDescription.fromRawDescriptors(conn.rawDescriptors)!! @@ -32,7 +35,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 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..735166d 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 @@ -41,7 +41,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 +134,13 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { } add(Item(R.string.euicc_info_ci_type, getString(resId))) } + add( + Item( + R.string.euicc_info_atr, + channel.atr?.encodeHex() ?: 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