Secure Element Access
A module to explicitly give trusted apps access to the secure element (eSE) by using a safer application ID based implementation, regardless of the ARF configuration on the eUICC. Additionally, it provides a way to toggle between eSIM and UIM modes for devices with non-removable eUICC.
Compatibility
- Android 10+
- Rooted devices with Xposed framework installed (e.g. LSPosed)
- Access can be granted to any of the following Local Profile Assistant (LPA) apps or a customized list:
- (OEM) com.google.android.euicc
- (FOSS) chat.jmp.simmanager
- (FOSS) im.angry.easyeuicc
Usage
| Feature | Scope |
|---|---|
| Allow privileged applications | com.android.se |
| Grant Qualcomm RIL permissions | system_server |
| Switch Qualcomm RIL eSIM/UIM modes | com.android.phone + system_server |
Switching between eSIM/UIM
On Qualcomm devices with a non-removable eUICC, an OEM hook tunnel can power cycle the eSIM slot and flip its persistent enable flag in the modem at /nv/item_files/modem/uim/uimdrv/esim_enable. This application provides a generic editor for that protocol: pick an action and a slot, adjust the payload if needed, then Send.
| Action | Message ID | Arguments |
|---|---|---|
| eSIM on | 86 | power=1, slot, ignore_hotswap=0, esim_enable=1 |
| eSIM off | 86 | power=0, slot, ignore_hotswap=0, esim_enable=0 |
| UIM on | 85 | power=1, slot, ignore_hotswap=0 |
| UIM off | 85 | power=0, slot, ignore_hotswap=-1 |
Implementation
On Android, eUICC APIs are by default restricted to whitelisted apps. This makes sense because most eUICC chips are integrated into the device. If someone wants to access the chip, say for instance to provision a profile, they generally need to do so through a Local Profile Assistant (LPA) app, which can either be
- a system app that provides EuiccService (in the case of an integrated eUICC), or
- a carrier app signed by a certificate whose hashes match the ARF/ACCF stored in the eUICC
In the case of a removable eSIM (such as those from sysmocom, estk.me or esim.me), the options are limited as they do not have control over device firmware. Users also have to rely heavily on carrier support for their apps as the ARF is baked into the eUICC itself.
However, there is a caveat. Likely to facilitate Android vendor testing, full access to the eUICC can also be granted if the ROM firmware is built with a debuggable flag, i.e. ro.debuggable=1, while configured to accept all channel access requests, persist.service.seek=fullaccess. Effectively, this translates to setting mUseAra and mUseArf fields to false while granting mFullAccess in com.android.se.security.AccessControlEnforcer according to the sources.
A previous version of this module enabled eSE access for third-party apps by patching these 3 flags directly in AccessControlEnforcer. However, that approach is more of a one-size-fits-all solution that does not distinguish potentially malicious apps from legitimate ones, posing a significant risk when enabled.
Tracing the source code to see how access can be more granularly provided, I found that app eligibility eventually comes down to the isPrivilegedApplication check in com.android.se.Terminal. There is no need to touch AccessControlEnforcer at all, as that check already operates on one of the default steps intended for carrier applications.
Therefore, this module instead modifies the response from that check without any drastic changes to how AccessControlEnforcer behaves. It is also possible to be even more specific with the patching, down to the exact application signature rather than using the application ID, but that would be more cumbersome to support and maintain.
For users who are still not entirely convinced of how secure this is, you are welcome to trim the list even further and include only your own application ID in your build. Since Android by default does not allow app signatures to be overwritten during updates, you should be protected as long as your custom LPA app is signed properly 👍