1

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());
    }   
}
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
Martin Clemens Bloch
  • 1,047
  • 1
  • 12
  • 28
  • Might help if we knew what type of card/NFC tag you are using. – Michael Roland Dec 01 '13 at 19:12
  • It's the 7.5 D contactless basiccard. Is there anywhere I could get more information on Androids transceive function or how to debug it? – Martin Clemens Bloch Dec 02 '13 at 05:44
  • You may check whether you run into a timeout situation. In such a case a wrong command would return quickly, but the operations on the card may take longer than the NFC stack waits for the tag to respond. In this case increasing the timeout value via setTimeout(int timeout) might help. – corvairjo Dec 03 '13 at 14:41
  • @corvairjo See edit2. – Martin Clemens Bloch Dec 19 '13 at 15:55
  • What commands do you send? What responses do you send/expect/get? What Android device are you using? – Michael Roland Dec 19 '13 at 16:17
  • @MichaelRoland See edit3 I will post my software version later.. I chose one of the low ones in order to support older phones maybe API 14-18. (NFC is introduced in API 10 or so.) – Martin Clemens Bloch Dec 19 '13 at 19:47
  • Okay, so now we are getting closer ;-) – Michael Roland Dec 19 '13 at 20:50
  • When you say you receive "null" from the card, do you mean that the transceive method actually returns `null` or that you receive an exception? Could you show us the code that you use to transceive commands with the card? – Michael Roland Dec 19 '13 at 21:22
  • `bitcoinCard` is of type NfcA (or better IsoDep), right? What does `getBytes()` do? When you say transceive fails or returns `null`, you hit the line `mainLabel.setText("Sent or received null.");`, right? – Michael Roland Dec 20 '13 at 11:03
  • It is NfcA, I will test IsoDep tomorrow. GetBytes converts a user string of numbers to a byte array, lets me debug using just the phone on the bus :) Transceive does not return null, it throws an exception. The null response is something I think I see when debugging the native code behind the transceive method. – Martin Clemens Bloch Dec 21 '13 at 18:23
  • See my updated answer regarding `NfcA` vs. `IsoDep`, though I'm really surprised that you get valid responses (error codes) in some cases. – Michael Roland Dec 22 '13 at 11:02

1 Answers1

3

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.
Michael Roland
  • 39,663
  • 10
  • 99
  • 206
  • I don't know about the IsoDep vs. NfcA, it seems to make no difference and the card is specifically NfcA whereas IsoDep is built on NfcA/NfcB. The only thing in the ZC manual about the CLA byte says that C0 is reserved for ZC commands. Their own examples use 20 for CLA... so I'm pissed about it, but simply changing the CLA to 80 did the trick. I don't know why I could return my own SW1/SW2 before.. maybe the android phone did something or I was redefining another command. – Martin Clemens Bloch Dec 23 '13 at 12:57
  • (Changing CLA to 80 also made P1/P2 be required by the card again.) – Martin Clemens Bloch Dec 23 '13 at 13:04
  • 2
    UPDATE: I wrote that IsoDep vs. NfcA makes no difference. I do not know why, but when I tested it last time that was really the case. Now however it DOES seem to make a difference. You must use IsoDep. – Martin Clemens Bloch Mar 01 '14 at 10:52