Making Host Card Emulation work for payment

2019-03-14 04:11发布

问题:

I've been using StackOverflow for years now, always finding answers to my questions before even asking them, but today I'm stuck.

As I happen to have a working POS terminal (the EMV Chip&Pin kind), I wanted to look into host card emulation.

The terminal works with the latest version of Tapp, so I know that the terminal is good and that my N7 with Kitkat can actually do payment (or at least the terminal do a series of good sounding bleeps and bloops, and the tablet launch Tapp's enrollment screen). So I've read the manual(s) and written a bunch of lines with the objective of seeing something arrive on my HostApduService. It partially works as I can find my dummy "card" in the Tap&Pay settings of the tablet.

But the "payment" part doesn't work: just two high-pitched bleeps from the POS terminal and nothing on the tablet. My HostApduService is not called.

I've tried all kind of different AIDs: real ones and silly ones, short and long, but nothing works.

When using Tapp, the LogCat says :

11-17 14:51:47.690: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x18
11-17 14:51:47.690: D/HostEmulationManager(3183): notifyHostEmulationActivated
11-17 14:51:47.690: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x17
11-17 14:51:47.690: D/BrcmNfcJni(3183): RoutingManager::stackCallback: NFA_CE_DATA_EVT; h=0x302; data len=20
11-17 14:51:47.690: D/HostEmulationManager(3183): notifyHostEmulationData
11-17 14:51:47.700: D/HostEmulationManager(3183): Service already bound as payment service.
11-17 14:51:47.700: D/HostEmulationManager(3183): Binding to existing service
11-17 14:51:49.932: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x19
11-17 14:51:49.932: D/HostEmulationManager(3183): notifyHostEmulationDeactivated
11-17 14:51:49.932: E/BrcmNfcNfa(3183): UICC[0x0] is not activated

And with my code, the LogCat is :

11-17 14:41:52.079: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x18
11-17 14:41:52.079: D/HostEmulationManager(3183): notifyHostEmulationActivated
11-17 14:41:52.089: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x17
11-17 14:41:52.089: D/BrcmNfcJni(3183): RoutingManager::stackCallback: NFA_CE_DATA_EVT; h=0x302; data len=20
11-17 14:41:52.089: D/HostEmulationManager(3183): notifyHostEmulationData
11-17 14:41:53.340: D/BrcmNfcJni(3183): RoutingManager::stackCallback: event=0x19
11-17 14:41:53.340: D/HostEmulationManager(3183): notifyHostEmulationDeactivated
11-17 14:41:53.340: E/BrcmNfcNfa(3183): UICC[0x0] is not activated

Obviously with my code, the OS doesn't bind the HCE intent to my service. But why?

You'll find below my manifest :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.remolagi.hcetestbanque2"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="19"
    android:targetSdkVersion="19" />

<uses-permission android:name="android.permission.NFC" />

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

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="net.remolagi.hcetestbanque2.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <service
        android:name=".MyHCEService"
        android:exported="true"
        android:permission="android.permission.BIND_NFC_SERVICE" >
        <intent-filter>
            <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
            <category android:name="android.intent.category.DEFAULT" />
       </intent-filter>

        <meta-data
            android:name="android.nfc.cardemulation.host_apdu_service"
            android:resource="@xml/apduservice" />
    </service>
</application>

</manifest>

my apduservice.xml :

<?xml version="1.0" encoding="UTF-8"?>

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/servicedesc" 
    android:requireDeviceUnlock="true"
    android:apduServiceBanner="@drawable/payment_banner">
<aid-group android:description="@string/aiddescription"
           android:category="payment">
    <aid-filter android:name="A0000000031010"/>
    </aid-group>
</host-apdu-service>

And for good measure, the service (as you can see at the moment, it does nothing except Logging) :

package net.remolagi.hcetestbanque2;

import android.nfc.cardemulation.HostApduService;
import android.os.Bundle;
import android.util.Log;

public class MyHCEService extends HostApduService {


    private static final String TAG = "MyHCEService";

    @Override
    public void onDeactivated(int arg0) {

        Log.i(TAG, "OnDeactivated - arg0 : " + String.valueOf(arg0));
        // TODO Auto-generated method stub

    }

    @Override
    public byte[] processCommandApdu(byte[] arg0, Bundle arg1) {

        Log.i(TAG, "Hooza ! processCommandApdu");

        return arg0;
    }

}

If you have ideas on why it doesn't work, I'll be forever grateful. For now, I'm stumped.

Regards

Philippe

回答1:

The first applet that will be selected by a EMV terminal is the PPSE applet, so you can try to add it also to your AID filters:

<aid-filter android:name="325041592E5359532E4444463031"/>

I don't know why you are trying to emulate payment with HCE but this will never be approved by Visa and MasterCard since for EMV transaction you need a cryptographic keys that need to be stored in secure environment. In the best case the HCE can be used for card not present transactions.



回答2:

I have noticed during my experiments that the POS device will try to select AID of its supported card scheme. You can check for supported schemes on the device by looking at symbols such as "Visa", "Mastercard" etc. There is a list of AIDs for these schemes at http://en.wikipedia.org/wiki/EMV down the page. So for example, if POS supports Mastercard credit/debit cards, you can try registering AID of mastercard:A0000000041010 as aid-filter in apduservice.xml without registering the AID for PPSE. Give it a go and let me know if it works please.

Edit: Please note that I have been using Vivo tech POS readers.



回答3:

A list with the PPSE, Mastercard and Visa:

<aid-group android:description="paymentGroup" android:category="payment">  
    <aid-filter android:name="325041592E5359532E4444463031" android:description="ppse"/> 
    <aid-filter android:name="A0000000041010" android:description="MasterCard"/> 
    <aid-filter android:name="A0000000031010" android:description="Visa"/>
</aid-group>


回答4:

host-apdu-service structure example:

For HCE application is really necessary to include PPSE AID entry:

apduservice.xml file:

<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:description="@string/servicedesc"
    android:requireDeviceUnlock="false" >

    <aid-group
        android:category="payment"
        android:description="@string/aiddescription" >

        <!-- Visa Proximity Payment System Environment - PPSE (2PAY.SYS.DDF01) -->
        <aid-filter android:name="325041592E5359532E4444463031" />

        <!-- VISA Debit/Credit (Classic)  -->
        <aid-filter android:name="A0000000031010" />

        <!-- VISA Credit -->
        <aid-filter android:name="A000000003101001" />

        <!-- VISA Debit -->
        <aid-filter android:name="A000000003101002" />

        <!-- VISA Electron (Debit) -->
        <aid-filter android:name="A0000000032010" />

        <!-- V PAY -->
        <aid-filter android:name="A0000000032020" />

        <!-- VISA Interlink -->
        <aid-filter android:name="A0000000033010" />

        <!-- MasterCard PayPass -->
        <aid-filter android:name="A00000000401" />

        <!-- MasterCard Credit -->
        <aid-filter android:name="A0000000041010" />

        <!-- American Express -->
        <aid-filter android:name="A000000025" />

        <!-- BRADESCO -->
        <aid-filter android:name="F0000000030001" />

    </aid-group>

</host-apdu-service>