From 92fbfc52296dcc9819bf5c4974d6b78cd3fb6742 Mon Sep 17 00:00:00 2001 From: septs Date: Tue, 1 Apr 2025 03:18:02 +0200 Subject: [PATCH 1/5] chore: add more isd-r aids (#184) Reviewed-on: https://gitea.angry.im/PeterCxy/OpenEUICC/pulls/184 Co-authored-by: septs Co-committed-by: septs --- .../angry/openeuicc/util/PreferenceUtils.kt | 28 +++++++++++++------ .../res/layout/activity_isdr_aid_list.xml | 1 + 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt index 928079f..5f4aec4 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/PreferenceUtils.kt @@ -45,11 +45,22 @@ const val EUICC_DEFAULT_ISDR_AID = "A0000005591010FFFFFFFF8900000100" internal object PreferenceConstants { val DEFAULT_AID_LIST = """ # One AID per line. Comment lines start with #. + # Refs: + # eUICC standard $EUICC_DEFAULT_ISDR_AID - - # 5ber + + # eSTK.me + A06573746B6D65FFFFFFFF4953442D52 + + # eSIM.me + A0000005591010000000008900000300 + + # 5ber.eSIM A0000005591010FFFFFFFF8900050500 + + # Xesim + A0000005591010FFFFFFFF8900000177 """.trimIndent() } @@ -97,13 +108,12 @@ class PreferenceFlowWrapper private constructor( defaultValue: T, encoder: (T) -> T, decoder: (T) -> T - ) : - this( - context, - key, - context.dataStore.data.map { it[key]?.let(decoder) ?: defaultValue }, - encoder - ) + ) : this( + context, + key, + context.dataStore.data.map { it[key]?.let(decoder) ?: defaultValue }, + encoder + ) suspend fun updatePreference(value: T) { context.dataStore.edit { it[key] = encoder(value) } diff --git a/app-common/src/main/res/layout/activity_isdr_aid_list.xml b/app-common/src/main/res/layout/activity_isdr_aid_list.xml index 06a75a1..48135fb 100644 --- a/app-common/src/main/res/layout/activity_isdr_aid_list.xml +++ b/app-common/src/main/res/layout/activity_isdr_aid_list.xml @@ -11,6 +11,7 @@ android:id="@+id/isdr_aid_list_editor" android:layout_width="0dp" android:layout_height="0dp" + android:fontFamily="monospace" android:importantForAutofill="no" android:inputType="textMultiLine" android:gravity="top|start" From 05abed117a71796648b0ab6ac51a60ad63b57e8c Mon Sep 17 00:00:00 2001 From: septs Date: Tue, 1 Apr 2025 03:18:22 +0200 Subject: [PATCH 2/5] fix: click sn copy (#186) Reviewed-on: https://gitea.angry.im/PeterCxy/OpenEUICC/pulls/186 Co-authored-by: septs Co-committed-by: septs --- .../src/main/java/im/angry/openeuicc/ui/EuiccInfoActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4e499dc..aa922be 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 @@ -104,7 +104,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker { add(Item(R.string.euicc_info_eid, channel.lpa.eID, copiedToastResId = R.string.toast_eid_copied)) channel.tryParseEuiccVendorInfo()?.let { vendorInfo -> vendorInfo.skuName?.let { add(Item(R.string.euicc_info_sku, it)) } - vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it)) } + vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it, copiedToastResId = R.string.toast_sn_copied)) } vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) } vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) } } From 3662f93760b6c418e89d585fa024e15f522f2ed0 Mon Sep 17 00:00:00 2001 From: septs Date: Tue, 1 Apr 2025 03:18:45 +0200 Subject: [PATCH 3/5] fix: send terminal capabilities (#187) fix 9eSIM v1 (G+D) on USB Reviewed-on: https://gitea.angry.im/PeterCxy/OpenEUICC/pulls/187 Co-authored-by: septs Co-committed-by: septs --- .../java/im/angry/openeuicc/core/usb/UsbApduInterface.kt | 9 +++++++++ 1 file changed, 9 insertions(+) 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 f9e764b..31ba333 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 @@ -45,6 +45,15 @@ class UsbApduInterface( e.printStackTrace() throw e } + + // Send Terminal Capabilities + // Specs: ETSI TS 102 221 v15.0.0 - 11.1.19 TERMINAL CAPABILITY + val terminalCapabilities = buildCmd( + 0x80.toByte(), 0xaa.toByte(), 0x00, 0x00, + "A9088100820101830107".decodeHex(), + le = null, + ) + transmitApduByChannel(terminalCapabilities, 0,) } override fun disconnect() { From 00ddf092874bf3aa863bed925eb2c6fddcc4eb0b Mon Sep 17 00:00:00 2001 From: septs Date: Tue, 1 Apr 2025 03:19:21 +0200 Subject: [PATCH 4/5] fix: improve lpa string parsing (#181) Reviewed-on: https://gitea.angry.im/PeterCxy/OpenEUICC/pulls/181 Co-authored-by: septs Co-committed-by: septs --- .../java/im/angry/openeuicc/util/LPAString.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt b/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt index 20956fb..63a81f1 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/LPAString.kt @@ -8,15 +8,15 @@ data class LPAString( ) { companion object { fun parse(input: String): LPAString { - val components = input.removePrefix("LPA:").split('$') - if (components.size < 2 || components[0] != "1") { - throw IllegalArgumentException("Invalid activation code format") - } + var token = input + if (token.startsWith("LPA:", ignoreCase = true)) token = token.drop(4) + val components = token.split('$').map { it.trim().ifBlank { null } } + require(components.getOrNull(0) == "1") { "Invalid AC_Format" } return LPAString( - address = components[1].trim(), - matchingId = components.getOrNull(2)?.trim()?.ifBlank { null }, - oid = components.getOrNull(3)?.trim()?.ifBlank { null }, - confirmationCodeRequired = components.getOrNull(4)?.trim() == "1" + requireNotNull(components.getOrNull(1)) { "SM-DP+ is required" }, + components.getOrNull(2), + components.getOrNull(3), + components.getOrNull(4) == "1" ) } } From 6c774450ec65924b6058338444379447b3d0d74f Mon Sep 17 00:00:00 2001 From: septs Date: Tue, 1 Apr 2025 23:13:57 +0200 Subject: [PATCH 5/5] fix: usb isd-r aid fallback (#188) Reviewed-on: https://gitea.angry.im/PeterCxy/OpenEUICC/pulls/188 Co-authored-by: septs Co-committed-by: septs --- .../core/DefaultEuiccChannelFactory.kt | 41 +++++++++++-------- .../core/DefaultEuiccChannelManager.kt | 6 +-- .../openeuicc/core/usb/UsbApduInterface.kt | 2 +- .../im/angry/openeuicc/util/StringUtils.kt | 13 +++--- .../core/PrivilegedEuiccChannelFactory.kt | 4 +- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt index b249675..870baae 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelFactory.kt @@ -60,11 +60,11 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha Log.i(DefaultEuiccChannelManager.TAG, "Is OMAPI channel, setting MSS to 60") it.lpa.setEs10xMss(60) } - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { // Failed Log.w( DefaultEuiccChannelManager.TAG, - "OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex}." + "OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex} with ISD-R AID: ${isdrAid.encodeHex()}." ) } @@ -80,20 +80,29 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha if (bulkIn == null || bulkOut == null) return null val conn = usbManager.openDevice(usbDevice) ?: return null if (!conn.claimInterface(usbInterface, true)) return null - return EuiccChannelImpl( - context.getString(R.string.usb), - FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)), - intrinsicChannelName = usbDevice.productName, - UsbApduInterface( - conn, - bulkIn, - bulkOut, - context.preferenceRepository.verboseLoggingFlow - ), - isdrAid, - context.preferenceRepository.verboseLoggingFlow, - context.preferenceRepository.ignoreTLSCertificateFlow, - ) + try { + return EuiccChannelImpl( + context.getString(R.string.usb), + FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)), + intrinsicChannelName = usbDevice.productName, + UsbApduInterface( + conn, + bulkIn, + bulkOut, + context.preferenceRepository.verboseLoggingFlow + ), + isdrAid, + context.preferenceRepository.verboseLoggingFlow, + context.preferenceRepository.ignoreTLSCertificateFlow, + ) + } catch (_: IllegalArgumentException) { + // Failed + Log.w( + DefaultEuiccChannelManager.TAG, + "USB APDU interface unavailable for ISD-R AID: ${isdrAid.encodeHex()}." + ) + } + return null } override fun cleanup() { diff --git a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt index 74ec285..ac9ba08 100644 --- a/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt +++ b/app-common/src/main/java/im/angry/openeuicc/core/DefaultEuiccChannelManager.kt @@ -277,11 +277,7 @@ open class DefaultEuiccChannelManager( ) try { val channel = tryOpenChannelFirstValidAid { - euiccChannelFactory.tryOpenUsbEuiccChannel( - device, - iface, - it - ) + euiccChannelFactory.tryOpenUsbEuiccChannel(device, iface, it) } if (channel != null && channel.lpa.valid) { usbChannel = channel 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 31ba333..107395f 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 @@ -53,7 +53,7 @@ class UsbApduInterface( "A9088100820101830107".decodeHex(), le = null, ) - transmitApduByChannel(terminalCapabilities, 0,) + transmitApduByChannel(terminalCapabilities, 0) } override fun disconnect() { diff --git a/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt b/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt index 9f993a3..079853e 100644 --- a/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt +++ b/app-common/src/main/java/im/angry/openeuicc/util/StringUtils.kt @@ -34,15 +34,12 @@ fun formatFreeSpace(size: Int): String = * If none is found, at least EUICC_DEFAULT_ISDR_AID is returned */ fun parseIsdrAidList(s: String): List = - s.split('\n').map(String::trim).filter { !it.startsWith('#') } + s.split('\n') .map(String::trim) - .mapNotNull { - try { - it.decodeHex() - } catch (_: IllegalArgumentException) { - null - } - } + .filter { !it.startsWith('#') } + .map(String::trim) + .filter(String::isNotEmpty) + .mapNotNull { runCatching(it::decodeHex).getOrNull() } .ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) } fun String.prettyPrintJson(): String { diff --git a/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt b/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt index 5489bd5..68eddef 100644 --- a/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt +++ b/app/src/main/java/im/angry/openeuicc/core/PrivilegedEuiccChannelFactory.kt @@ -44,11 +44,11 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.ignoreTLSCertificateFlow, ) - } catch (e: IllegalArgumentException) { + } catch (_: IllegalArgumentException) { // Failed Log.w( DefaultEuiccChannelManager.TAG, - "TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex}, falling back" + "TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex} with ISD-R AID: ${isdrAid.encodeHex()}." ) } }