Android NFC: как маршрутизировать APDU для одного определенного AID для защиты элемента UICC (маршрутизация вне хоста)

У меня есть SIM-карта с апплетом (карточкой) на нем. Если я могу установить для защищенного элемента по умолчанию на устройстве Android значение UICC, я могу отправлять команды через бесконтактный интерфейс в UICC.

Мой считыватель NFC отправляет APDU с "SELECT AID A0000001234567890" на контроллер NFC, который отправляет его моему апплету на защищенном элементе UICC (контроль доступа позаботился).

Теперь я хочу, чтобы это работало для устройств, где я не могу установить для защищенного элемента по умолчанию значение UICC.

Если я все правильно понял, так как для этого мне принципиально не нужно приложение Android, мне, тем не менее, придется использовать фиктивное приложение Android и объявить в своем манифесте так называемую "службу вне хоста".

Может ли кто-нибудь подсказать мне, что мне нужно сделать, чтобы маршрутизировать APDU, которые выбирают AID моего апплета, установленного на защищенном элементе, и последующие APDU к защищенному элементу UICC?

Вот моя первая попытка, но, возможно, у кого-то есть рабочий пример для меня или некоторые рекомендации / исправления.

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>

1 ответ

Решение

Ваш старт выглядит хорошо, и использование offhost-apdu-service должно нормально работать на устройствах, которые поддерживают обмен данными между эмуляцией карты и защищенным элементом. Обратите внимание, что некоторые устройства просто не поддерживают это, хотя.

Однако есть некоторые проблемы с вашими файлами XML:

  1. Служба эмуляции карт в категории оплаты должна объявлять ресурс баннера отрисовываемым ресурсом. Баннер службы должен представлять собой графический файл (например, файл.png) с размерами 260 x 96 пикселей.

    <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. Службы должны быть объявлены в теге приложения в файле манифеста (обратите внимание, что я также изменяю имя службы, чтобы избежать конфликтов с именами класса framework):

    <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. Помимо объявления сервиса в вашем манифесте, вам также необходимо создать реализацию Java для сервиса. Что-то вроде:

    public class MyOffHostApduService extends OffHostApduService {
        public IBinder onBind(Intent intent) {
            return null;
        }
    }
    
  4. <uses-feature ...> а также <uses-permission ...> элементы должны быть прямыми дочерними элементами <manifest> элемент (т.е. на том же уровне, что и <application ...> элемент. Их нельзя использовать внутри других тегов (например, тег службы в вашем случае):

    <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. <uses-library ...> элемент должен быть прямым потомком <application ...> элемент. Тем не менее, вы, вероятно, не используете эту библиотеку в любом случае и можете полностью ее удалить.

Наконец, обратите внимание, что AID в вашем примере недопустим, поскольку он не выравнивается по полным байтам. Например, действительный AID будет A00000012345678900, (Хотя я предполагаю, что это просто произошло во время маскировки вашего исходного AID для примера, верно?)

Другие вопросы по тегам