Compare commits

...

2 commits

Author SHA1 Message Date
6b4723daee refactor: ATR should not be the concern of lpac-jni
Some checks failed
/ build-debug (push) Has been cancelled
...instead, use a separate interface to represent channel types that do
support reading ATR.
2024-12-20 19:30:33 -05:00
3ef78a23db feat: atr in euiccinfo activity
commit 0fbec512ab
Author: septs <github@septs.pw>
Date:   Wed Dec 18 21:27:53 2024 +0800

    feat: atr in euiccinfo activity
2024-12-20 19:06:23 -05:00
8 changed files with 38 additions and 5 deletions

View file

@ -0,0 +1,5 @@
package im.angry.openeuicc.core
interface ApduInterfaceAtrProvider {
val atr: ByteArray?
}

View file

@ -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

View file

@ -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<Boolean>,
ignoreTLSCertificateFlow: Flow<Boolean>
) : 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

View file

@ -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()

View file

@ -15,7 +15,7 @@ class OmapiApduInterface(
private val service: SEService,
private val port: UiccPortInfoCompat,
private val verboseLoggingFlow: Flow<Boolean>
): 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()
}

View file

@ -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<Boolean>
): 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

View file

@ -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<Int, Int>): String =

View file

@ -31,6 +31,7 @@
<string name="toast_profile_delete_confirm_text_mismatched">Confirmation string mismatch</string>
<string name="toast_iccid_copied">ICCID copied to clipboard</string>
<string name="toast_eid_copied">EID copied to clipboard</string>
<string name="toast_atr_copied">ATR copied to clipboard</string>
<string name="usb_permission">Grant USB permission</string>
<string name="usb_permission_needed">Permission is needed to access the USB smart card reader.</string>
@ -132,6 +133,8 @@
<string name="euicc_info_ci_gsma_live">GSMA Live CI</string>
<string name="euicc_info_ci_gsma_test">GSMA Test CI</string>
<string name="euicc_info_ci_unknown">Unknown eSIM CI</string>
<string name="euicc_info_atr">ATR (Answer To Reset)</string>
<string name="euicc_info_atr_unavailable">ATR unavailable</string>
<string name="yes">Yes</string>
<string name="no">No</string>