# Android APDU proxy Android APDU proxy is an Android app that provides a bridge between a host computer and the UICC/eUICC slot of an Android smartphone. The connection is done via a normal TCP connection. Once the proxy is connected, applications on the host computer, such as pySim-shell can access the UICC/eUICC inside the phone remotely, just as if it were plugged into a local reader. ![image](screenshot.jpg) Interfaces ---------- ### OMAPI OMAPI (Open Mobile API) is an Android API to access secure elements (SE). This also includes UICCs and eUICCs. OMAPI allows to access an SE on APDU level, but there are limitations however. The APDU access is only possible on a higher level to avoid security problems. For example it is not possible to select a card application directly (SELECT by DF-Name). Instead, an OMAPI specific API call must be made. The Android APDU proxy adopts for such limitations as transparent as possible. The following limitations apply: * OMAPI works on APDU, not TPDU level, there is no conversion layer implemented, so the UICC or eUICC will appear as a T=1 only smartcard on the remote end. This is still spec compliant (see also ETSI TS 102 221, section 7.2) * No logical channel support. Even though it is possible to open multiple channels to an SE via OMAPI, the Android APDU proxy only offers access to a single channel. Any attempt to send a MANAGE CHANNEL command is rejected with an 6D00 status word. * SELECT by DF-Name is not allowed. OMAPI does not allow to send a SELECT command that selects an ADF via its DF-Name (AID). This is due to security reasons as any card application must be registered correctly in the ARA-M configuration on the card with appropriate access rights, so that OMAPI is allowed to open a channel to that card application. Since it is not possible to perform a SELECT by DF-Name, such APDUs will be translated to either a normal select to FID 7FFF (which is the alias for the currently selected application) or the current OMAPI channel is closed and re-opened to the application that the APDU attempted to select. In case the re-opening if the OMAPI channel fails, the Android APDU proxy will return a 6A82 status word. More information about OMAPI can be found under: * https://source.android.com/docs/security/features/open-mobile-api * https://developer.android.com/reference/android/se/omapi/package-summary * https://globalplatform.org/wp-content/uploads/2018/04/GPD_Open_Mobile_API_Spec_v3.2.0.13_PublicReview.pdf ### VPCD The VPCD interface is a virtual smartcard reader that provides a TCP interface on its backend. To that backend virtual smartcard implementations or similar applications can connect and respond to ATR requests and APDUs. On the frontend VPCD behaves like a normal PC/SC smartcard reader. This means that in theory any PC/SC capable application, such as pySim-shell, is able to access UICC/eUICCs via the Android APDU proxy. More information about VPCD and how to install it can be found under: * https://frankmorgner.github.io/vsmartcard/virtualsmartcard/README.html More information about pySim-shell can be found under: * https://gitea.osmocom.org/sim-card/pysim Setting up VPCD --------------- A detailed description on how to setup the VPCD service can be found on the project website (see above). When the VPCD service is properly installed, the service should run at localhost on port 35963 (0x8C7B) and two new (virtual) smartcard readers (we will only use `Virtual PCD 00 00`) should appear in the output of `pcsc_scan`. ``` PC/SC device scanner V 1.6.2 (c) 2001-2022, Ludovic Rousseau Using reader plug'n play mechanism Scanning present readers... 0: Virtual PCD 00 00 1: Virtual PCD 00 01 2: Alcor Micro AU9540 00 00 Thu Nov 14 11:10:48 2024 Reader 0: Virtual PCD 00 00 Event number: 2 Card state: Card removed, Reader 1: Virtual PCD 00 01 Event number: 0 Card state: Card removed, Reader 2: Alcor Micro AU9540 00 00 Event number: 2 Card state: Card removed, ``` Unfortunately it is not possible to bind the VPCD service to an external IP address using its configuration. To make the VPCD service available from outside anyway, we may use `socat`. ``` $ socat tcp-listen:8000,reuseaddr,fork tcp:localhost:35963 ``` Connecting the APDU proxy ------------------------- ### Configuration To connect the APDU proxy, the `Android APDU proxy` application is started on the Android device. The application will do a quick scan for available UICC/eUICC cards. The first available UICC/eUICC is preselected. In case the Android device has multiple card slots with different cards, the user can select the UICC/eUICC using the `card slot` drop-down menu. The text field `remote host` sets the IP-Address of the host where the VPCD service is running. The user must edit the text field accordingly. The text field `remote port` sets the port where the VPCD service is running. This field must match the port number from the `socat` commandline (see above). The values entered in `remote host` and `remote port` are saved in the application settings. It is not necessary to re-enter the values on every start of the application. ### Connection The connection is started by pressing the `CONNECT` button. When the connection is successfully made, the indicator light `ATR traffic` should start flashing. The APDU proxy is now connected and the VPCD service is querying the ATR from the UICC/eUICC regulary. Also the UICC/eUICC should now appear in `pcsc_scan`. The card is now available to the user as a normal PC/SC smartcard. To access the UICC/eUICC the user may now use pySim-shell (or any other PC/SC capable utility) to access the card: ``` $ ./pySim-shell.py -p 0 Using reader PCSC[Virtual PCD 00 00] Waiting for card... Warning: Could not detect card type - assuming a generic card type... Info: Card is of type: UICC AIDs on card: USIM: a0000000871002ffffffff8907090000 (EF.DIR) ISIM: a0000000871004ffffffff8907090000 (EF.DIR) Welcome to pySim-shell! (C) 2021-2023 by Harald Welte, sysmocom - s.f.m.c. GmbH and contributors Online manual available at https://downloads.osmocom.org/docs/pysim/master/html/shell.html pySIM-shell (00:MF)> ``` While accessing the card, indicator `Channel` should be lit and the `APDU traffic` indicator should change its state (flash, may stay lit) whenever an APDU is exchanged. To terminate the connection either the `EXIT` button or the `DISCONNECT` button must be pressed. Pressing the home button will just minimize the application, but not terminate the connection. Build from source ----------------- To build the APK file from source, the Android SDK, platform and build-tools must be installed. You must also accept the licenses. ``` # apt-get install android-sdk sdkmanager # sdkmanager 'platforms;android-34' # sdkmanager 'build-tools;34.0.0' # sdkmanager --licenses ``` Adjust the path to `test_keystore.jks` in `app/build.gradle.kts`. A test keystore is part of this git repository. To use it, put the absolute path into `build.gradle.kts`. The build fails if no keystore is specified. The build process can the be started from the project directory: ``` $ export ANDROID_HOME=/usr/lib/android-sdk/ $ ./gradlew :app:assembleRelease ``` When the build process is done, an `app-release.apk` file should be present in ./app/build/outputs/apk/release. This file can be installed on the Android device. Signing and ARA-M configuration ------------------------------- The OMAPI interface requires Android applications to be signed and the SHA-1 digest of the signing certificate must be put into the ARA-M configuration of the UICC/eUICC. If this is not done correctly the APDU proxy will still connect and exchange ATR traffic, but it won't be able to exchange APDUs with the UICC/eUICC. By default, the build process will use the provided test signing keys from `test_keystore.jks`. In case a specific signing key should be used, the user may edit app/build.gradle.kts accordingly. To find the SHA-1 digest of the APK file, one can use the `apksigner` utility to dump the relevant information: ``` $ apksigner verify --print-certs ./app/build/outputs/apk/release/app-release.apk Signer #1 certificate DN: C=US, ST=test, L=test, O=test labs, OU=test department, CN=John Doe Signer #1 certificate SHA-256 digest: 506d2b5cdd8dfadb0353f1ea305315ee14df06a3ebbe7270a575c5ce083502c2 Signer #1 certificate SHA-1 digest: 51e3450094304ad64de318db166b0283acb5cdb4 Signer #1 certificate MD5 digest: f037d7fde5decf6d833bc85ca76f7fd3 ``` In this example `51e3450094304ad64de318db166b0283acb5cdb4` is the SHA-1 digest that has to be registered in the ARA-M configuration. Changing the ARA-M configuration may be vendor specific. For `sysmoISIM` cards that use the ARA-M applet from Bertrand Martel, the ARA-M configuration can be changed using the following pySim-shell commandlines: ``` select ADF.ARA-M aram_store_ref_ar_do --aid "" --device-app-id "51e3450094304ad64de318db166b0283acb5cdb4" --apdu-always --android-permissions "0000000000000001" ``` Troubleshooting --------------- In case the android application does not work and the displayed error messages are not sufficient to identify the problem, it is still possible to view the debug log using `logcat` to debug the problem further. Such logs are in particular helpful in case a bug report has to be filed. To enable the debug log of the android application the application must be configured as `debugable` during the build process. This is done by using the gradlew parameter `assembleDebug` instead of `assembleRelease`. This creates an 'apk-debug.apk' in ./app/build/outputs/apk/release. The release application must be removed from the Android device and 'apk-debug.apk' must then be installed on the Android device. The log can then be viewed using the following commandline: ``` $ adb logcat ``` It may make sense to log to a file or filter the output using `grep` Pre-built APK packages ---------------------- Pre-built (nightly) APK packages are avilable for download under: * https://jenkins.osmocom.org/jenkins/job/master-android-apdu-proxy/a1=default,a2=default,a3=default,a4=default,label=osmocom-master/ Re-signing APK -------------- In case the user already has an ARA-M configuration with matching signing keys, it is possible to use the `apksigner` utility to re-sign an already existing APK file with those keys. The following commandline will re-sign `app-release.apk` with `myKey` from the user specified keystore `/path/to/my/keystore.jks`. ``` $ apksigner sign --ks-key-alias myKey --ks-pass "pass:myPassword" --ks /path/to/my/keystore.jks ./app/build/outputs/apk/release/app-release.apk ``` To make sure that the re-signing was successful the apksigner utility can be used as already described in section `Signing and ARA-M configuration`