ISO 7816-4 APDU command Select File and Write Record

Bao Doan picture Bao Doan · Apr 15, 2014 · Viewed 12.1k times · Source

I am trying to communicate between PN532 and HCE on Android with ISO 7816-4 command, I am successfully select the AID (a DF), but when I select the EF under that DF (that EF does not exist, so I assume that Select command will create that EF), and then write the records to that EF but it display like this:

inList passive target
write:  4A 1 0
read:   4B 1 1 0 4 60 4 8 23 5A 4D 5 75 80 70 2
write:  40 1 0 A4 4 0 7 F0 1 2 3 4 5 6 0
read:   41 0 48 65 6C 6C 6F 20 44 65 73 6B 74 6F 70 21

Successfully hehe 

48 65 6C 6C 6F 20 44 65 73 6B 74 6F 70 21    Hello Desktop!
write:  40 1 0 A4 2 C 1 1 0
read:   41 0 48 65 6C 6C 6F 20 44 65 73 6B 74 6F 70 21
Not enough space
write:  40 1 0 D2 0 0 7 42 41 4F 47 49 41 40 0
read:   41 0 4D 65 73 73 61 67 65 20 66 72 6F 6D 20 61 6E 64 72 6F 69 64 3A 20 30
Not enough space
write:  40 1 0 D2 0 2 4 44 4F 41 4E 0
read:   41 0 4D 65 73 73 61 67 65 20 66 72 6F 6D 20 61 6E 64 72 6F 69 64 3A 20 31
Not enough space
write:  40 1 0 B2 0 0 7 42 41 4F 47 49
read:   41 0 4D 65 73 73 61 67 65 20 66 72 6F 6D 20 61 6E 64 72 6F 69 64 3A 20 32
Not enough space
write:  40 1 0 B2 0 2 4 44 4F 41 4E 0
read:   41 0 4D 65 73 73 61 67 65 20 66 72 6F 6D 20 61 6E 64 72 6F 69 64 3A 20 33
Not enough space

I don't know what I am doing wrong here?

On Android, the log is :

04-15 09:36:54.024: D/HostEmulationManager(929): notifyHostEmulationData
04-15 09:36:54.024: W/System.err(17710): [B@41ed5970
04-15 09:36:54.024: I/HCEDEMO(17710): Received: ???????BAOGI
04-15 09:36:54.024: D/HostEmulationManager(929): Sending data
04-15 09:36:54.164: D/BrcmNfcJni(929): RoutingManager::stackCallback: event=0x17
04-15 09:36:54.164: D/BrcmNfcJni(929): RoutingManager::stackCallback: NFA_CE_DATA_EVT;       h=0x302; data len=10
04-15 09:36:54.164: D/HostEmulationManager(929): notifyHostEmulationData
04-15 09:36:54.164: W/System.err(17710): [B@41ed5e20
04-15 09:36:54.164: I/HCEDEMO(17710): Received: ?????DOAN??
04-15 09:36:54.174: D/HostEmulationManager(929): Sending data
04-15 09:36:54.885: D/BrcmNfcJni(929): RoutingManager::stackCallback: event=0x19
04-15 09:36:54.885: D/HostEmulationManager(929): notifyHostEmulationDeactivated
04-15 09:36:54.885: I/HCEDEMO(17710): Deactivated: 0
04-15 09:36:54.885: D/HostEmulationManager(929): Unbinding from service  ComponentInfo{de.grundid.hcedemo/de.grundid.hcedemo.MyHostApduService}
04-15 09:36:54.895: E/BrcmNfcNfa(929): UICC[0x0] is not activated

It displays that it can receive some data, but it misses some elements I want to transmit, but, from PN532, when I use read records, it does not display these data?

Answer

Michael Roland picture Michael Roland · Apr 15, 2014

The commands that your Android HCE emulated smartcard application understands and processes are completely up to you (as long as they are formatted as valid ISO 7816-4 APDUs).

In your case, your Android HCE service obviously processes the SELECT (by DF name) APDU,

00 A4 04 00 07 F0010203040506 00

and gives this as a response:

48 65 6C 6C 6F 20 44 65 73 6B 74 6F 70 21 ("Hello Desktop!" when interpreted as ASCII)

(Note that this response is not a valid response APDU according to ISO 7816-4 as it lacks a status word.)

The next command you send is an invalid SELECT (by EF) command:

00 A4 02 0C 01 01 00

For that command, Lc should be 2 and the EF identifier should consist of two bytes if following ISO 7816-4. In response to that, your Android HCE service again sends

48 65 6C 6C 6F 20 44 65 73 6B 74 6F 70 21 ("Hello Desktop!" when interpreted as ASCII)

(Note that this response is not a valid response APDU according to ISO 7816-4 as it lacks a status word.)

So I would guess, that your Android HCE service performs a check like this:

public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
    if (apdu[1] == (byte)0xA4) {
        return "Hello Desktop!".getBytes("US-ASCII");
    }
}

The next command that you send is a malformed WRITE RECORD command that tries to write "BAOGIA@" in the first record of the cuirrently selected file (malformed, because a WRITE RECORD command normally does not have an Le field):

00 D2 00 00 07 42 41 4F 47 49 41 40 00

As a response your Android HCE service sends:

4D 65 73 73 61 67 65 20 66 72 6F 6D 20 61 6E 64 72 6F 69 64 3A 20 30 ("Message from android: 0" when interpreted as ASCII)

(Note that this response is again not a valid response APDU according to ISO 7816-4 as it lacks a status word.)

You then repeat the WRITE RECORD command with a different record payload and after that you send two malformed READ RECORD commands:

00 D2 00 02 04 44 4F 41 4E 00
00 B2 00 00 07 42 41 4F 47 49
00 B2 00 02 04 44 4F 41 4E 00

As a response your Android HCE service sends:

4D 65 73 73 61 67 65 20 66 72 6F 6D 20 61 6E 64 72 6F 69 64 3A 20 xx ("Message from android: X" when interpreted as ASCII)

Where xx seems to be an ASCII digit X that is incremented for each received command.

So I would guess, that your Android HCE service looks like this:

private int mCommandCounter = 0;
public byte[] processCommandApdu(byte[] apdu, Bundle extras) {
    String response;
    if (apdu[1] == (byte)0xA4) {
        response = "Hello Desktop!";
    } else {
        response = "Message from android: " + Integer.toString(mCommandCounter);
        ++mCommandCounter;
    }
    return response.getBytes("US-ASCII");
}

So, to summarize this, your Android HCE service will understand and process only those commands that you (or whoever develops it) implement. So it is up to you what commands you can send to the HCE device. There is no file system behind it. ISO 7816-4 only suggests a file system layout for smartcard applications.