Compare commits

..

No commits in common. "6c774450ec65924b6058338444379447b3d0d74f" and "d7bfd84de925735957b780e3f53f6510c95c8303" have entirely different histories.

9 changed files with 49 additions and 71 deletions

View file

@ -60,11 +60,11 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
Log.i(DefaultEuiccChannelManager.TAG, "Is OMAPI channel, setting MSS to 60") Log.i(DefaultEuiccChannelManager.TAG, "Is OMAPI channel, setting MSS to 60")
it.lpa.setEs10xMss(60) it.lpa.setEs10xMss(60)
} }
} catch (_: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
// Failed // Failed
Log.w( Log.w(
DefaultEuiccChannelManager.TAG, DefaultEuiccChannelManager.TAG,
"OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex} with ISD-R AID: ${isdrAid.encodeHex()}." "OMAPI APDU interface unavailable for physical slot ${port.card.physicalSlotIndex}."
) )
} }
@ -80,7 +80,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
if (bulkIn == null || bulkOut == null) return null if (bulkIn == null || bulkOut == null) return null
val conn = usbManager.openDevice(usbDevice) ?: return null val conn = usbManager.openDevice(usbDevice) ?: return null
if (!conn.claimInterface(usbInterface, true)) return null if (!conn.claimInterface(usbInterface, true)) return null
try {
return EuiccChannelImpl( return EuiccChannelImpl(
context.getString(R.string.usb), context.getString(R.string.usb),
FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)), FakeUiccPortInfoCompat(FakeUiccCardInfoCompat(EuiccChannelManager.USB_CHANNEL_ID)),
@ -95,14 +94,6 @@ open class DefaultEuiccChannelFactory(protected val context: Context) : EuiccCha
context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.verboseLoggingFlow,
context.preferenceRepository.ignoreTLSCertificateFlow, 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() { override fun cleanup() {

View file

@ -277,7 +277,11 @@ open class DefaultEuiccChannelManager(
) )
try { try {
val channel = tryOpenChannelFirstValidAid { val channel = tryOpenChannelFirstValidAid {
euiccChannelFactory.tryOpenUsbEuiccChannel(device, iface, it) euiccChannelFactory.tryOpenUsbEuiccChannel(
device,
iface,
it
)
} }
if (channel != null && channel.lpa.valid) { if (channel != null && channel.lpa.valid) {
usbChannel = channel usbChannel = channel

View file

@ -45,15 +45,6 @@ class UsbApduInterface(
e.printStackTrace() e.printStackTrace()
throw e 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() { override fun disconnect() {

View file

@ -104,7 +104,7 @@ class EuiccInfoActivity : BaseEuiccAccessActivity(), OpenEuiccContextMarker {
add(Item(R.string.euicc_info_eid, channel.lpa.eID, copiedToastResId = R.string.toast_eid_copied)) add(Item(R.string.euicc_info_eid, channel.lpa.eID, copiedToastResId = R.string.toast_eid_copied))
channel.tryParseEuiccVendorInfo()?.let { vendorInfo -> channel.tryParseEuiccVendorInfo()?.let { vendorInfo ->
vendorInfo.skuName?.let { add(Item(R.string.euicc_info_sku, it)) } vendorInfo.skuName?.let { add(Item(R.string.euicc_info_sku, it)) }
vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it, copiedToastResId = R.string.toast_sn_copied)) } vendorInfo.serialNumber?.let { add(Item(R.string.euicc_info_sn, it)) }
vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) } vendorInfo.firmwareVersion?.let { add(Item(R.string.euicc_info_fw_ver, it)) }
vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) } vendorInfo.bootloaderVersion?.let { add(Item(R.string.euicc_info_bl_ver, it)) }
} }

View file

@ -8,15 +8,15 @@ data class LPAString(
) { ) {
companion object { companion object {
fun parse(input: String): LPAString { fun parse(input: String): LPAString {
var token = input val components = input.removePrefix("LPA:").split('$')
if (token.startsWith("LPA:", ignoreCase = true)) token = token.drop(4) if (components.size < 2 || components[0] != "1") {
val components = token.split('$').map { it.trim().ifBlank { null } } throw IllegalArgumentException("Invalid activation code format")
require(components.getOrNull(0) == "1") { "Invalid AC_Format" } }
return LPAString( return LPAString(
requireNotNull(components.getOrNull(1)) { "SM-DP+ is required" }, address = components[1].trim(),
components.getOrNull(2), matchingId = components.getOrNull(2)?.trim()?.ifBlank { null },
components.getOrNull(3), oid = components.getOrNull(3)?.trim()?.ifBlank { null },
components.getOrNull(4) == "1" confirmationCodeRequired = components.getOrNull(4)?.trim() == "1"
) )
} }
} }

View file

@ -45,22 +45,11 @@ const val EUICC_DEFAULT_ISDR_AID = "A0000005591010FFFFFFFF8900000100"
internal object PreferenceConstants { internal object PreferenceConstants {
val DEFAULT_AID_LIST = """ val DEFAULT_AID_LIST = """
# One AID per line. Comment lines start with #. # One AID per line. Comment lines start with #.
# Refs: <https://euicc-manual.osmocom.org/docs/lpa/applet-id-oem/>
# eUICC standard # eUICC standard
$EUICC_DEFAULT_ISDR_AID $EUICC_DEFAULT_ISDR_AID
# eSTK.me # 5ber
A06573746B6D65FFFFFFFF4953442D52
# eSIM.me
A0000005591010000000008900000300
# 5ber.eSIM
A0000005591010FFFFFFFF8900050500 A0000005591010FFFFFFFF8900050500
# Xesim
A0000005591010FFFFFFFF8900000177
""".trimIndent() """.trimIndent()
} }
@ -108,7 +97,8 @@ class PreferenceFlowWrapper<T> private constructor(
defaultValue: T, defaultValue: T,
encoder: (T) -> T, encoder: (T) -> T,
decoder: (T) -> T decoder: (T) -> T
) : this( ) :
this(
context, context,
key, key,
context.dataStore.data.map { it[key]?.let(decoder) ?: defaultValue }, context.dataStore.data.map { it[key]?.let(decoder) ?: defaultValue },

View file

@ -34,12 +34,15 @@ fun formatFreeSpace(size: Int): String =
* If none is found, at least EUICC_DEFAULT_ISDR_AID is returned * If none is found, at least EUICC_DEFAULT_ISDR_AID is returned
*/ */
fun parseIsdrAidList(s: String): List<ByteArray> = fun parseIsdrAidList(s: String): List<ByteArray> =
s.split('\n') s.split('\n').map(String::trim).filter { !it.startsWith('#') }
.map(String::trim) .map(String::trim)
.filter { !it.startsWith('#') } .mapNotNull {
.map(String::trim) try {
.filter(String::isNotEmpty) it.decodeHex()
.mapNotNull { runCatching(it::decodeHex).getOrNull() } } catch (_: IllegalArgumentException) {
null
}
}
.ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) } .ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) }
fun String.prettyPrintJson(): String { fun String.prettyPrintJson(): String {

View file

@ -11,7 +11,6 @@
android:id="@+id/isdr_aid_list_editor" android:id="@+id/isdr_aid_list_editor"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
android:fontFamily="monospace"
android:importantForAutofill="no" android:importantForAutofill="no"
android:inputType="textMultiLine" android:inputType="textMultiLine"
android:gravity="top|start" android:gravity="top|start"

View file

@ -44,11 +44,11 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
context.preferenceRepository.verboseLoggingFlow, context.preferenceRepository.verboseLoggingFlow,
context.preferenceRepository.ignoreTLSCertificateFlow, context.preferenceRepository.ignoreTLSCertificateFlow,
) )
} catch (_: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
// Failed // Failed
Log.w( Log.w(
DefaultEuiccChannelManager.TAG, DefaultEuiccChannelManager.TAG,
"TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex} with ISD-R AID: ${isdrAid.encodeHex()}." "TelephonyManager APDU interface unavailable for slot ${port.card.physicalSlotIndex} port ${port.portIndex}, falling back"
) )
} }
} }