forked from PeterCxy/OpenEUICC
Compare commits
5 commits
d7bfd84de9
...
6c774450ec
Author | SHA1 | Date | |
---|---|---|---|
6c774450ec | |||
00ddf09287 | |||
3662f93760 | |||
05abed117a | |||
92fbfc5229 |
9 changed files with 71 additions and 49 deletions
|
@ -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 (e: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
// Failed
|
// Failed
|
||||||
Log.w(
|
Log.w(
|
||||||
DefaultEuiccChannelManager.TAG,
|
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,6 +80,7 @@ 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)),
|
||||||
|
@ -94,6 +95,14 @@ 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() {
|
||||||
|
|
|
@ -277,11 +277,7 @@ open class DefaultEuiccChannelManager(
|
||||||
)
|
)
|
||||||
try {
|
try {
|
||||||
val channel = tryOpenChannelFirstValidAid {
|
val channel = tryOpenChannelFirstValidAid {
|
||||||
euiccChannelFactory.tryOpenUsbEuiccChannel(
|
euiccChannelFactory.tryOpenUsbEuiccChannel(device, iface, it)
|
||||||
device,
|
|
||||||
iface,
|
|
||||||
it
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (channel != null && channel.lpa.valid) {
|
if (channel != null && channel.lpa.valid) {
|
||||||
usbChannel = channel
|
usbChannel = channel
|
||||||
|
|
|
@ -45,6 +45,15 @@ 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() {
|
||||||
|
|
|
@ -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)) }
|
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.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)) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,15 +8,15 @@ data class LPAString(
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(input: String): LPAString {
|
fun parse(input: String): LPAString {
|
||||||
val components = input.removePrefix("LPA:").split('$')
|
var token = input
|
||||||
if (components.size < 2 || components[0] != "1") {
|
if (token.startsWith("LPA:", ignoreCase = true)) token = token.drop(4)
|
||||||
throw IllegalArgumentException("Invalid activation code format")
|
val components = token.split('$').map { it.trim().ifBlank { null } }
|
||||||
}
|
require(components.getOrNull(0) == "1") { "Invalid AC_Format" }
|
||||||
return LPAString(
|
return LPAString(
|
||||||
address = components[1].trim(),
|
requireNotNull(components.getOrNull(1)) { "SM-DP+ is required" },
|
||||||
matchingId = components.getOrNull(2)?.trim()?.ifBlank { null },
|
components.getOrNull(2),
|
||||||
oid = components.getOrNull(3)?.trim()?.ifBlank { null },
|
components.getOrNull(3),
|
||||||
confirmationCodeRequired = components.getOrNull(4)?.trim() == "1"
|
components.getOrNull(4) == "1"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,11 +45,22 @@ 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
|
||||||
|
|
||||||
# 5ber
|
# eSTK.me
|
||||||
|
A06573746B6D65FFFFFFFF4953442D52
|
||||||
|
|
||||||
|
# eSIM.me
|
||||||
|
A0000005591010000000008900000300
|
||||||
|
|
||||||
|
# 5ber.eSIM
|
||||||
A0000005591010FFFFFFFF8900050500
|
A0000005591010FFFFFFFF8900050500
|
||||||
|
|
||||||
|
# Xesim
|
||||||
|
A0000005591010FFFFFFFF8900000177
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,8 +108,7 @@ 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 },
|
||||||
|
|
|
@ -34,15 +34,12 @@ 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').map(String::trim).filter { !it.startsWith('#') }
|
s.split('\n')
|
||||||
.map(String::trim)
|
.map(String::trim)
|
||||||
.mapNotNull {
|
.filter { !it.startsWith('#') }
|
||||||
try {
|
.map(String::trim)
|
||||||
it.decodeHex()
|
.filter(String::isNotEmpty)
|
||||||
} catch (_: IllegalArgumentException) {
|
.mapNotNull { runCatching(it::decodeHex).getOrNull() }
|
||||||
null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) }
|
.ifEmpty { listOf(EUICC_DEFAULT_ISDR_AID.decodeHex()) }
|
||||||
|
|
||||||
fun String.prettyPrintJson(): String {
|
fun String.prettyPrintJson(): String {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
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"
|
||||||
|
|
|
@ -44,11 +44,11 @@ class PrivilegedEuiccChannelFactory(context: Context) : DefaultEuiccChannelFacto
|
||||||
context.preferenceRepository.verboseLoggingFlow,
|
context.preferenceRepository.verboseLoggingFlow,
|
||||||
context.preferenceRepository.ignoreTLSCertificateFlow,
|
context.preferenceRepository.ignoreTLSCertificateFlow,
|
||||||
)
|
)
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (_: IllegalArgumentException) {
|
||||||
// Failed
|
// Failed
|
||||||
Log.w(
|
Log.w(
|
||||||
DefaultEuiccChannelManager.TAG,
|
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()}."
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue