Android NfcA Transceive fails on success

5.3k views Asked by At

I made a simple test application for quick debugging. I send some bytes, print what I sent on the phones screen and print what I receive.

When I send WRONG commands I get the corresponding error codes in the two byte SW1SW2. I can also call my own command and override SW1SW2 with my own values and I can get them.

Here's the problem: When I send a CORRECT command the transceive command fails with the informative exception "Transceive failed".

If I send the correct command, but override SW1SW2 to something other than 90 00 then I get the SW value I set, but NO response data. (likely because the card does not send ODATA when SW1SW2 <> 90 00)

So how come I'm so sure I sent correct commands? Well other than messing with my own test command I called the GetAppId command - which failed saying I have to define AppId in the card. So I define it in the card, send the same command and transceive fails.

So I'm pretty sure the problem is that transceiving fails when there is ODATA, but I do not understand WHY or how to FIX it.. help please!

EDIT: My card is the 7.5 D contactless basiccard from ZeitControl.

EDIT2: I have set the timeout to 2000ms with no change in behavior. I'm trying to return a single byte of data and the system command I called also doesn't sound heavy.

Then I downloaded and attached the Android source and debugged. There was some segments it would still not go into - but the card seems to return null on valid commands unless I return some manually set SW1SW2 in which case that is the only thing received.

EDIT3: The system command I tried was: 192 14 0 0 0 (or C0 0E 00 00 00) (or CLA INS P1 P2 Lc) I'm not 100% sure I'm doing that one correctly, but I have tried with various lengths (up to 22) of Le and without Le as above and only without does it not give me 6700 (wrong Le/Lc) Of course instead of 6700 it returns null it seems...

The other command is my own defined as 20 0A (value as Byte) and no P1/P2 specified in the .BAS file. I call that one with: 32 10 1 0 1 (or 20 0A 01 00 01) (or CLA INS Lc IDATA Le) This should mean 1 byte data in, set to 0, and 1 byte expected out (+ SW1/SW2 as always). (Setting P1/P2 gives 6700 so unless defined in the command declaration I dont think they should be there) This also returns null. I Expect 00 90 00 to be returned here. (if I set "value" to 00 that is)

I'm using a HTC One X.

EDIT4: MinSdk version = 14 and target 18.

if(bitcoinCard  != null){
try {
    String sentmsg, receivedmsg;
    byte[] send = getBytes(commandBytes.getText().toString());
    byte[] data = null;
    if(send != null){
        bitcoinCard.setTimeout(2000);
        data = bitcoinCard.transceive(send);
}
        //bitcoinCard.close();
        /*if(data != null && data.length == 2)
        {
            mainLabel.setText("SW1SW2: " + (data[0] < 0 ? -data[0] + 
128 : data[0]) + " " + (data[1] < 0 ? -data[1] + 128 : data[1]));
        }else */if (data != null && send != null)
        {
            sentmsg = "" + (send[0] < 0 ? send[0] + 256 : send[0]);
            for(int i = 1; i < send.length; i++)
            {
                sentmsg = sentmsg + " " + (send[i] < 0 ? send[i] + 
256 : send[i]);
            }
            receivedmsg = "" + (data[0] < 0 ? data[0] + 256 : data[0]);
            for(int i = 1; i < data.length; i++)
            {
                receivedmsg = receivedmsg + " " + (data[i] < 0 ? data[i] + 256 : data[i]);
            }
            mainLabel.setText("Sent: " + sentmsg + "\n" +
                              "Response: " + 
receivedmsg);
        }else
        {
            mainLabel.setText("Sent or received null.");
        }
    } catch (IOException e) {

        mainLabel.setText("Tried to talk to card, but had error: " + 
e.getMessage());
    }   
}
1

There are 1 answers

3
Michael Roland On BEST ANSWER

First, when you send APDUs you should use an IsoDep object (and not NfcA). Android should show both tag technologies as available for your card. The problem here is that Android will typically only activate the card in ISO 14443-4 protocol mode if you use IsoDep. Thus, wehn using NfcA, your card will not be ready to accept APDUs.

I just tested and this is at least the case on a Nexus S with Android 4.1.2. In fact trying to transceive using the NfcA object leads to TagLostExceptions with some cards and to some other really odd behavior with another card I tried.

Second, if you send

byte[] cmd = { (byte)0xC0, (byte)0x0E, (byte)0x00, (byte)0x00, (byte)0x00 };

I would expect the card to return the actual application ID. However, the answer to this command (i.e. <data> <SW1=61> <SW2=len>) does not comply to ISO 7816-4 (no data should be returned for a 61xx status code) so this might cause a problem.

UPDATE: I just tested this with a Nexus S (Android 4.1.2) and receiving such responses was not a problem.

Last, your other command (20 0A) is not what you expect it to be:

  1. I strongly suggest you only use CLA bytes set to 0x00 or 0x80 unless you know what you are doing (use of secure messaging, use of logical channels, ...). Though, Android (at least with NXP's NFC chipset) does not care about the structure of the APDU, but your card might!
  2. An APDU always has the form <CLA> <INS> <P1> <P2> [Lc [DATA]] <Le> (with the special case of <CLA> <INS> <P1> <P2>). So this means you cannot simply omit P1 and P2.
  3. You are correct in that BasicCard will discard ODATA if SW<>9000 and SW1<>61.