5

I'm busy with an app to emulate normal APDU communication on a Nexus 7 with CM10.1 to an ACR122U102 reader/writer. I found this blog about software card emulation and wrote an app to make my device (the nexus) appear as a card. Now I'm trying to send messages back and forth between this device and the ACR122u. So far, I've only managed to communicate with the nexus 7 by sending D4 40 01 (InDataExchange page 127) APDU's. For the application I'm writing, this should be sufficient.

The problem lays in the answer I send from the device to the reader. Using the transcieve function (android.nfc.tech.IsoPcdA with reflection), I can reply with a byte array of length > 0. This would show up on the reader-end like a normal InDataExchange response (e.g: D5 41 00 01 02 03 with {01 02 03} being the byte array supplied to the transcieve function). But I can't control the status byte nor the SW bytes in the response (D5 41 XX and both SW's). There's no documentation to be found about this IsoPcdA class except the source code itself.

What I want to be able to do is change the XX to a byte of my choice and to send answers of length = 0 (e.g: D5 41 01 without any extra data). Is it possible?

Michael Roland
  • 39,663
  • 10
  • 99
  • 206
Fons
  • 155
  • 1
  • 9

1 Answers1

6

I'm not exactly sure what you are trying to achieve here. Whatever you transceive with IsoPcdA's transceive method are complete APDUs (as defined in ISO/IEC 7816-4, or rather any PDU within the ISO-DEP transport protocol). So the return value of transceive is a full C-APDU (command APDU) and the byte array parameter of transceive is a full R-APDU (response APDU) including the two bytes of the status word (SW1 | SW2). Thus, the last two bytes of that parameter are the status word. In your example SW1 would be 02 and SW2 would be 03.

What you see as status byte in the InDataExchange command of the PN532 NFC controller is not the status word of the APDU but the status of the command execution within the PN532 NFC controller. This status byte gives you information about buffer overflows, communication timeouts, etc and is not something that is returned by the card side.

EDIT : Sample code + test commands:

Sample Code running on Galaxy Nexus (CM 10):

try {
  Class isoPcdA = Class.forName("android.nfc.tech.IsoPcdA");
  Method isoPcdA_get = isoPcdA.getDeclaredMethod("get", Tag.class);

  final IsoPcdA techIsoPcdA = (IsoPcdA)isoPcdA_get.invoke(null, tag);

  if (techIsoPcdA != null) {
    if (mWorker != null) {
      mInterrupt = true;
      mWorker.interrupt();
      try {
        mWorker.join();
      } catch (Exception e) {}
    }

    mInterrupt = false;
    mWorker = new Thread(new Runnable() {
      public void run () {
        try {
          techIsoPcdA.connect();

          byte[] command = techIsoPcdA.transceive(new byte[]{ (byte)0x90, (byte)0x00 });
          Log.d(CardEmulationTest.class.getName(), "Connected.");

          while (!mInterrupt) {
            Log.d(CardEmulationTest.class.getName(), "C-APDU=" + StringUtils.convertByteArrayToHexString(command));
            command = techIsoPcdA.transceive(command);
          }
        } catch (Exception e) {
          Log.e(CardEmulationTest.class.getName(), "Exception while communicating on IsoPcdA object", e);
        } finally {
          try {
            techIsoPcdA.close();
          } catch (Exception e) {}
        }
      }
    });

    mWorker.start();
  }
} catch (Exception e) {
  Log.e(CardEmulationTest.class.getName(), "Exception while processing IsoPcdA object", e);
}

Test (using ACR122U):

InListPassivTargets (1 target at 106kbps)

> FF00000004 D44A 0100 00
< D54B 010100046004088821310578338800 9000

InDataExchange with DATA = 0x01

> FF00000004 D440 01 01 00
< D541 00 01 9000

So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).

InDataExchange with DATA = 0x01 0x02

> FF00000005 D440 01 0102 00
< D541 00 0102 9000

So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 0x02 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).

InDataExchange with DATA = 0x01 0x02 0x03

> FF00000006 D440 01 010203 00
< D541 00 010203 9000

So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 0x02 0x03 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).

InDataExchange with DATA = 0x01 0x02 0x03 0x04

> FF00000007 D440 01 01020304 00
< D541 00 01020304 9000

So we get an error code of 0x00 from the card reader (status of InDataExchange command; not part of the actual response APDU), we get 0x01 0x02 0x03 0x04 as the response (this is the IsoDepA response APDU) and we get 0x9000 as the status code for the card reader wrapper APDU (not part of the actual response APDU).

Thus, we get exactly the data taht we send as command APDU as response APDU (note that none of these APDUs is formatted according to ISO 7816-4, but that doesnt matter as the IsoPcdA card emulation works with any ISO 14443-4 transport protocol format).

The status code of 0x9000 belongs to the card reader APDU encapsulation (CLA=FF INS=00 P1P2=0000 Lc [PN542 COMMAND] Le=00) that is required as the ACR122U's PN532 is accessed over the CCID (PC/SC) interface. These are pure reader command encapsulation and have nothing to do with the communication over ISO-DEP.

The D440 01 [DATA] is the PN532 command to exchange data (e.g. APDUs) over ISO-DEP and the D541 00 [DATA] is the associated response.

Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • In the first place, it's this status byte (you're talking about on the last line) I want to be able to control. The current problem is I can only return 'success' R-APDU's. What I want to be able to is to respond with another status byte than 00 (eg, with a timeout 01 status code). – Fons May 27 '13 at 20:39
  • 1
    BTW, is this (http://www.mroland.at/fileadmin/mroland/tutorials/201209_NFCCongress_AndroidNFCWorkshop_slides.pdf) yours? I've read it yesterday and it made me think controlling the full ADPU with card emulation on Android is possible because you have listed ISO-7816 smartcards as Type 4 tag, which is exactly what the first link in the question tells is possible with SCE on Android. – Fons May 27 '13 at 20:48
  • 1
    Controlling the full APDU is possible (as I wrote in my answer). However, the "status byte" you are refering to is not part of the APDU. That status byte is part of the communication between your reader application and your reader chip. There is no way you could influence that on the APDU level. – Michael Roland Jul 23 '13 at 14:38
  • Yes, that's my tutorial. – Michael Roland Jul 23 '13 at 14:47
  • 1
    Still, emulating a normal communication between the reader and the nexus 7 is not completely possible. When I use transcieve on the IsoPcdA, the argument I provide does not hold the SW bytes. They are automatically added. When I provide {0x01}, the bytes {0x90, 0x00} show up on the other end appended to the 0x01. And sending zero-length APDUs isn't possible either (like a mifare OK for an authentication). Do you have any solution for that? – Fons Jul 24 '13 at 09:00
  • I've just tested using a Galaxy Nexus (CM 10) and an ACR122U using the samle code and the commands provided in my answer above and it works as expected (any ISO-DEP communication is possible, no status bytes are automatically added). – Michael Roland Jul 25 '13 at 03:38
  • Thanks, great edit! The SWs (9000) can't be changed unless something really goes wrong, correct? What you didn't try in the code was the zero-length response (data). Is there a way to change the PN532 header status byte? For instance, a response (as seen by the pc) as D541 13 9000 (I know this is Mifare which isn't 14443-4, but still). I guess not? @Michael – Fons Jul 25 '13 at 07:04
  • Correct, if that's the status word you are refering to: it can't be changed, and it would not make sense to (it's only command wrapping). Regarding the zero-length response: I didn't test because my Android app simply echos all received commands as response and its not possible to send an empty command with InDataExchange. I'm not sure if empty responses are valid according to the ISO-DEP specification. – Michael Roland Jul 25 '13 at 20:32
  • Again: Setting the status byte of the InDataExchange response is not possible and would not make any sense (as this status byte only indicates command execution status for InDataExchange). I'm not sure what you mean with "Mifare" -- there's no Mifare involved here The error response "D541 13 9000" indicates an RF framing error. – Michael Roland Jul 25 '13 at 20:33
  • Also, I wouldn't hold up too much with the details of the InDataExchange commands. If you use a proper reader (one that's PC/SC compliant and does not abuse PC/SC as command tunneling protocol like the ACR122U and derivates) you will be able to transparently send and receive properly formatted APDUs as specified in ISO 7816-4. – Michael Roland Jul 25 '13 at 20:35
  • The error I meant was 14, not 13. My mistake:) But probably is will still not work. Thanks anyway! – Fons Jul 26 '13 at 07:15
  • You should never get error code 0x14 for InDataExchange with any ISO-DEP card. (Error 14 indicates a Mifare authentication error which could only happen when you use the Mifare PCD functionality.) – Michael Roland Jul 26 '13 at 14:13