0

I wanted to answer this question so I wrote the below program:

package test;

import javacard.framework.APDU;
import javacard.framework.ISO7816;
import javacard.framework.Applet;
import javacard.framework.ISOException;
import javacard.framework.Util;

public class Test extends Applet {

    public static final byte[] res = { (byte) 0x00, (byte) 0x00, (byte) 0x3B,
            (byte) 0xAD, (byte) 0x3F, (byte) 0x00, (byte) 0x01, (byte) 0x00,
            (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x16,
            (byte) 0xB3, (byte) 0x03, (byte) 0x06, (byte) 0x04, (byte) 0x00,
            (byte) 0x83, (byte) 0x8A, (byte) 0x83, (byte) 0x8A, (byte) 0x00,
            (byte) 0x03, (byte) 0x00, (byte) 0x00, (byte) 0x3B, (byte) 0xAD,
            (byte) 0x00, (byte) 0x00, (byte) 0x3B, (byte) 0xAD, (byte) 0x2F,
            (byte) 0x06, (byte) 0x02 };

    public static void install(byte[] bArray, short bOffset, byte bLength) {
        new test.Test()
                .register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    }

    public void process(APDU apdu) {
        if (selectingApplet()) {
            return;
        }

        byte[] buf = apdu.getBuffer();

        if (buf[ISO7816.OFFSET_CLA] == 0xA0 && buf[ISO7816.OFFSET_INS] == 0xA4 && buf[ISO7816.OFFSET_P1] == 0x00 && buf[ISO7816.OFFSET_P2] == 0x00
                && buf[ISO7816.OFFSET_LC] == 0x02 && buf[ISO7816.OFFSET_LC+1] == 0x7F && buf[ISO7816.OFFSET_LC+2] == 0x20) {
            ISOException.throwIt((short) 0x9F23);
        } else if (buf[ISO7816.OFFSET_CLA] == 0xA0 && buf[ISO7816.OFFSET_INS] == 0xC0 && buf[ISO7816.OFFSET_P1] == 0x00
                && buf[ISO7816.OFFSET_P2] == 0x00 && buf[ISO7816.OFFSET_EXT_CDATA] == 0x23) {
            Util.arrayCopyNonAtomic(res, (short)0, buf, (short)0, (short)35);
            apdu.setOutgoingAndSend((short)0, (short)35);

        }
                else
                    ISOException.throwIt((short)0x9090);
    }
}

And install it as default selected using GlobalPlatformPro tool:

CMD> gp -install e:\soq.cap -default

CMD>

Well, now, I expect to have the following communication :

>> in: 0xA0 A4 00 00 02 7F 20 
<< out: 0x9F 23 
>> in : 0xA0 C0 00 00 23 
<< out: 0x00 00 3B AD 3F 00 01 00 00 00 00 00 16 B3 03 06 04 00 83 8A 83 8A 00 03 00 00 3B AD 00 00 3B AD 2F 06 02

But in real, I have the below communication using OpenSC :

CMD> OSC.exe -s A0A40000027F20 -s a0c0000023
Using reader with a card: ACS CCID USB Reader 0
Sending: A0 A4 00 00 02 7F 20
Received (SW1=0x90, SW2=0x90)
Sending: A0 C0 00 00 23
Received (SW1=0x90, SW2=0x90)

Update:

As dear @Vojta said in his answer, I cast the constants to bytes as below :

//.
//. These parts didn't changed
//.

public void process(APDU apdu) {
    if (selectingApplet()) {
        return;
    }

    byte[] buf = apdu.getBuffer();

    if (buf[ISO7816.OFFSET_CLA] == (byte)0xA0 && buf[ISO7816.OFFSET_INS] == (byte) 0xA4 && buf[ISO7816.OFFSET_P1] == (byte) 0x00&& buf[ISO7816.OFFSET_P2] == (byte) 0x00 
            && buf[ISO7816.OFFSET_LC] == (byte) 0x02 && buf[ISO7816.OFFSET_LC + 1] == (byte) 0x7F  && buf[ISO7816.OFFSET_LC + 2] == (byte) 0x20) {
        ISOException.throwIt((short) 0x9F23);
    } else if (buf[ISO7816.OFFSET_CLA] == (byte) 0xA0 && buf[ISO7816.OFFSET_INS] == (byte) 0xC0  && buf[ISO7816.OFFSET_P1] == (byte) 0x00 
            && buf[ISO7816.OFFSET_P2] == (byte) 0x00  && buf[ISO7816.OFFSET_EXT_CDATA] == (byte) 0x23 ) {
        Util.arrayCopyNonAtomic(res, (short) 0, buf, (short) 0, (short) 35);
        apdu.setOutgoingAndSend((short) 0, (short) 35);

    } else {
        ISOException.throwIt((short) 0x9090);
    }

//.
//. These parts didn't changed
//.

After installing the above applet as default selected applet, I receive the following reslts:

CommandLine> OSC.exe -s A0A40000027F20 -s a0c0000023
Using reader with a card: ACS CCID USB Reader 0
Sending: A0 A4 00 00 02 7F 20
Received (SW1=0x9F, SW2=0x23)
Sending: A0 C0 00 00 23
Received (SW1=0x90, SW2=0x90)

Well, as you see above, I receive the correct answer for first APDU command, but the answer of second APDU command is not as we expected.

I modify the second comparison section as below :

//.
//. These parts didn't changed
//.

else if (buf[ISO7816.OFFSET_CLA] == (byte) 0xA0 && buf[ISO7816.OFFSET_INS] == (byte) 0xC0  && buf[ISO7816.OFFSET_P1] == (byte) 0x00 
                && buf[ISO7816.OFFSET_P2] == (byte) 0x00  && buf[ISO7816.OFFSET_P2+1] == (byte) 0x23 ) { 

//.
//. These parts didn't changed
//.

Well, as you see I replaced buf[ISO7816.OFFSET_EXT_CDATA] with buf[ISO7816.OFFSET_P2+1], and now it works as I wanted:

CommandLine> OSC.exe -s A0A40000027F20 -s a0c0000023
Using reader with a card: ACS CCID USB Reader 0
Sending: A0 A4 00 00 02 7F 20
Received (SW1=0x9F, SW2=0x23)
Sending: A0 C0 00 00 23
Received (SW1=0x90, SW2=0x00):
00 00 3B AD 3F 00 01 00 00 00 00 00 16 B3 03 06 ..;.?...........
04 00 83 8A 83 8A 00 03 00 00 3B AD 00 00 3B AD ..........;...;.
2F 06 02                                        /..

I don't have any idea why I must use ISO7816.OFFSET_P2+1 instead of ISO7816.OFFSET_EXT_CDATA! I was thought 0x23 in the A0C0000023 APDU command, must consider as Le!(And not Lc).

Community
  • 1
  • 1
Ebrahim Ghasemi
  • 5,850
  • 10
  • 52
  • 113

1 Answers1

3

A0 and A4 are values greater than 128. Java Card bytes are signed, unfortunately. You have to cast your short constants to bytes before comparison.

Ebrahim Ghasemi
  • 5,850
  • 10
  • 52
  • 113
vojta
  • 5,591
  • 2
  • 24
  • 64
  • Thanks dear Vojta. Your answer solved the issue, but I face a new problem. I update the question, please take a look at it. – Ebrahim Ghasemi Jul 21 '15 at 03:49
  • As far as I knoe, `0x23` in the `A0C0000023` Command, is not neither `OFFSET_CDATA`, nor `OFFSET_EXT_CDATA`. It is `Le`, i.e length of expected data in the APDU Response. Am I right? – Ebrahim Ghasemi Jul 23 '15 at 14:52
  • @Abraham Oh, sorry, my previous comment is wrong, I will delete it. In Java Card you can get the Le value as the output of setIncomingAndReceive method. OFFSET_EXT_CDATA does not mean Le. – vojta Jul 24 '15 at 06:10
  • 1
    Ah dear Vojta, I guess I found something in your last comment that need to be corrected for future viewer. It's the `setOutgoing()` method that returns the `Le` value, not the `setIncomingAndReceive()` method. Return value of the latter is the length of the data field that card received for current APDU command so far. Kindly regards :) – Ebrahim Ghasemi Jun 10 '16 at 06:30