androidroutesnfcapdusecure-element

Android NFC: How to route APDUs for one certain AID to secure element UICC (Off-Host-Routing)


I have a SIM card with an applet (cardlet) on it. If I can set the default secure element in an Android device to UICC I can send commands via contactless interface to UICC.

My NFC reader sends an APDU with a "SELECT AID A0000001234567890" to the NFC controller which shall send it to my applet on the UICC secure element (access control has been taken care of).

Now I want to make this work for devices where I cannot set the default secure element to UICC.

If I understood everything correctly, as I do not need an Android application for this in principle, I nevertheless have to make use of a dummy Android application and declare a so-called "off-host service" in its manifest.

Can someone guide me what I need to do to route the APDUs that select the AID of my applet installed on the secure element and the subsequent APDUs to the UICC secure element?

Here is my first attempt, but maybe someone has a working example for me or some guidance/corrections.

AndroidManifest.xml:

<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc.hce" android:required="true" />

<service android:name=".OffHostApduService" android:exported="true"
    android:permission="android.permission.BIND_NFC_SERVICE">
<intent-filter>
    <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/>
</intent-filter>
<meta-data android:name="android.nfc.cardemulation.off_host_apdu_service"
    android:resource="@xml/apduservice"/>
<uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
</service>
<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">

    <activity android:name=".Echo">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <uses-library
            android:name="com.android.nfc_extras"
            android:required="true" />
    </activity>
</application>

apduservices.xml:

<offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android" android:description="@string/servicedesc">
<aid-group android:description="@string/subscription" android:category="payment">
<aid-filter android:name="A0000001234567890"/>
    </aid-group>
</offhost-apdu-service>

Solution

  • Your start looks fine and using an offhost-apdu-service should work fine on devices that support routing card emulation communication to a secure element. Note that some devices simply do not support this though.

    There are some issues with your XML files though:

    1. A card emulation service in category payment must declare a service banner drawable resource. The service banner should be a graphic file (e.g. a .png file) with dimensions of 260 x 96 pixels.

      <offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
          android:description="@string/servicedesc"
          android:apduServiceBanner="@drawable/servicebanner">
      
          <aid-group android:category="payment"
                     android:description="@string/servicedesc" >
              <aid-filter ... />
          </aid-group>
      </offhost-apdu-service>
      
    2. Services must be declared within the application tag in your manifest file (note that I also change the name of the service to avoid conflicts with the naming of the framework class):

      <application ...>
          <activity ...>
              ...
          </activity>
      
          <service android:name=".MyOffHostApduService" android:exported="true"
                   android:permission="android.permission.BIND_NFC_SERVICE">
              <intent-filter>
                  <action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE" />
              </intent-filter>
              <meta-data android:name="android.nfc.cardemulation.off_host_apdu_service"
                         android:resource="@xml/apduservice" />
          </service>
      </application>
      
    3. Besides declaring the service in your manifest, you also need to actually create the Java implementation for the service. Something like:

      public class MyOffHostApduService extends OffHostApduService {
          public IBinder onBind(Intent intent) {
              return null;
          }
      }
      
    4. <uses-feature ...> and <uses-permission ...> elements must be direct child elements of the <manifest> element (i.e. on the same level as the <application ...> element. They must not be used inside other tags (like the service tag in your case):

      <manifest ...>
          <uses-permission android:name="android.permission.NFC" />
          <uses-feature android:name="android.hardware.nfc" android:required="true" />
          <uses-feature android:name="android.hardware.nfc.hce" android:required="true" />
          <application ...>
      
    5. The <uses-library ...> element must be a direct child of the <application ...> element. However, you probably don't use this library anyways and can completely drop that.

    Finally, note that the AID in your example is not valid since it does not align on full bytes. A valid AID would, for example, be A00000012345678900. (Though I assume that this just happend during masking your original AID for the example, right?)