Christmas is coming soon! To thank for the support from all our dear customers, Christmas promotional activity is going on in JavaCardOS online store. For more activities details, please check this post.

Testing command success on JCIDE but failed on real card?

JavaCard Applet Development Related Questions and Answers.
leonard
Posts: 25
Joined: Wed Nov 18, 2015 12:13 am
Points :176
Contact:

Testing command success on JCIDE but failed on real card?

Post by leonard » Thu Dec 03, 2015 6:47 am

I develop an applet which return some simulate bytes data(6 bytes) when it receive Read Records command from host application. I use ACS ACR 38 card reader to access to card.
I test applet with JCIDE, it work well.
I also test it with virtual card reader by using pyApdutool, it work well too.

But when I install applet on a card by using pyApdutool, use the same Read Records command, the card return "Unknown error" message.
The applet was installed successful, using pyApdutool can select applet on the card.

Here is Read Records command:
[0x00 0xB3 0x00 0xFF]

I use etOutgoingAndSend() method to send data out

Code: Select all

apdu.setOutgoingAndSend((short) 0, (short)6) 


Could you explain to me what is wrong here?
Thanks
You do not have the required permissions to view the files attached to this post. Please login first.
Last edited by leonard on Thu Dec 03, 2015 10:26 pm, edited 1 time in total.

leonard
Posts: 25
Joined: Wed Nov 18, 2015 12:13 am
Points :176
Contact:

Re: Testing command success on JCIDE but failed on real card?

Post by leonard » Thu Dec 03, 2015 10:05 pm

Is anyone can help me out !
For more detail, here is my code, please try and let me know why it don't work on real card if you can.
Many thanks.

Code: Select all

package PTCRecords;
import javacard.framework.*;

public class PTCRecords extends Applet {
    // class of instructions
    private final static byte CLA = (byte) 0x00;
   
    // instruction codes
    private final static byte INS_SELECT        = (byte) 0xA4;  // select
    private final static byte INS_READ_R        = (byte) 0xB2;  // read record
    private final static byte INS_READ_RS       = (byte) 0xB3;  // read records
   

    // instruction parameters
    private final static byte P1_SEL_DF         = (byte) 0x04;  // select DF
    private final static byte P2_SEL_DF         = (byte) 0xC0;  //
    private final static byte P1_SEL_EF         = (byte) 0x02;  // select EF
    private final static byte P2_SEL_EF         = (byte) 0xC0;  //
    private final static byte P1_RD_R16         = (byte) 0x10;  // read record #16
    private final static byte P1_RD_R8          = (byte) 0x08;  // read record #4
    private final static byte P1_RD_R5          = (byte) 0x05;  // read record #1
    private final static byte P2_RD_R           = (byte) 0x04;  //
    private final static byte P1_RD_RS          = (byte) 0x00;  // read records
    private final static byte P2_RD_RS          = (byte) 0xFF;  //

    // EF No.
    private final static byte NO_EF0            = (byte) 0x00;  // DF
    private final static byte NO_EF1            = (byte) 0x01;  // EF1
    private final static byte NO_EF2            = (byte) 0x02;  // EF2
    private final static byte NO_EF3            = (byte) 0x03;  // EF3
    private final static byte NO_EF4            = (byte) 0x04;  // EF4
    private final static byte NO_EF5            = (byte) 0x05;  // EF5
    private final static byte NO_EF6            = (byte) 0x06;  // EF6
    private final static byte NO_EF7            = (byte) 0x07;  // EF7

    //only for test
    private final static short ARRAY_SIZE = 256;
/*
    // EF data                   FID   Recordlen  MaxRecordNum
    private byte [][] dataEF1;  // 4001  05         16
    private byte [][] dataEF2;  // 4002  08         08
    private byte [][] dataEF3;  // 4003  16         05
    private byte [][] dataEF4;  // 4004  05         16
    private byte [][] dataEF5;  // 4005  08         08
    private byte [][] dataEF6;  // 4006  16         05
    private byte [][] dataEF7;  // 4007  05         16
*/
    private byte[] outBuffer;
//    private byte   currentEF;
    private byte[]   currentEF;   // hirose 150127
//static byte currentEF;

    /**
     * Constructor
     */
    private PTCRecords(byte[] bArray, short bOffset, byte bLength) {
       currentEF = JCSystem.makeTransientByteArray((short)1, JCSystem.CLEAR_ON_DESELECT);
        currentEF[0] = NO_EF0;   // hirose 150127

        // create a transient buffer
        outBuffer = new byte[ARRAY_SIZE];
       

    }

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

   }
   
    public boolean select() {
       
       
        return true;
    } // select
   
    public void process(APDU apdu) {
        //Insert your code here
        byte[] buf = apdu.getBuffer();

        // the selectingApplet() is used in the applet process method to distinguish
        // the SELECT APDU command, which selected this applet, from all other SELECT
        // APDU commands. Returns true if this applet is being selected
        if (selectingApplet()) {
            currentEF[0] = NO_EF0;   // hirose 150127
            ISOException.throwIt(ISO7816.SW_NO_ERROR);
            return;
        }

        // verify if the applet can accept this APDU message
        if (buf[ISO7816.OFFSET_CLA] != CLA) {
            ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
        }
        switch (buf[ISO7816.OFFSET_INS]) {
         case INS_SELECT:
                    selectEF(apdu);
                break;
            case INS_READ_R:  // 0xB2: read record
                ReadRecord(apdu);
                break;
               
            case INS_READ_RS:  // 0xB3: read records
                //0x00 0xB3 0x00 0xFF
                if((buf[ISO7816.OFFSET_P1] == P1_RD_RS)
                    && (buf[ISO7816.OFFSET_P2] == P2_RD_RS))
                {   // 0x00FF: ReadRecords
                    ReadRecors(apdu);
                } else {
                    ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
                }
                break;
            default:
                ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);
        }
    }

    private void selectEF(APDU apdu) {
        // select
        byte buffer[] = apdu.getBuffer();
        currentEF[0] = buffer[ISO7816.OFFSET_CDATA+1];   

        ISOException.throwIt(ISO7816.SW_NO_ERROR);
    }

    private void ReadRecord(APDU apdu) {
        // ReadRecord
        byte buffer[] = apdu.getBuffer();
        byte len=0;
        byte record=0;
        byte cnt=0;
        len = buffer[ISO7816.OFFSET_LC];
        record = buffer[ISO7816.OFFSET_P1];

        switch(currentEF[0]){   
        case NO_EF1:   // EF#1
        case NO_EF4:   // EF#4
        case NO_EF7:   // EF#7
            if( record > P1_RD_R16){
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
           break;
        case NO_EF2:   // EF#2
        case NO_EF5:   // EF#5
            if( record > P1_RD_R8){
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
           break;
        case NO_EF3:   // EF#3
        case NO_EF6:   // EF#6
            if( record > P1_RD_R5){
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
           break;
        }

        // set data
        getData( buffer, (byte)(0), (byte)len , currentEF[0]);   

      // send data
        apdu.setOutgoingAndSend((short) 0, (short) len);
    }

    private void ReadRecors(APDU apdu) {
        byte buffer[] = apdu.getBuffer();
        byte lc = 0;
        byte idxLen = 0;
        byte len = 0;
        byte cnt = 0;
        if( buffer[ISO7816.OFFSET_CDATA] != 0x53){
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }

        lc = buffer[ISO7816.OFFSET_LC];
        idxLen = buffer[ISO7816.OFFSET_CDATA+1];
        if( lc != idxLen+2){
               ISOException.throwIt(ISO7816.SW_WRONG_DATA);
        }

        for( cnt = 0;cnt<idxLen;cnt+=4){
            switch(buffer[(byte)(ISO7816.OFFSET_CDATA+cnt+3)]){
            case NO_EF1:   // EF#1
            case NO_EF4:   // EF#4
            case NO_EF7:   // EF#7
                len += 5;
                break;
            case NO_EF2:   // EF#2
            case NO_EF5:   // EF#5
                len += 8;
                break;
            case NO_EF3:   // EF#3
            case NO_EF6:   // EF#6
                len += 16;
                break;
            }
        }

      getData( buffer, (byte)(0), (byte)5 , (byte)1);
      getData( buffer, (byte)(5), (byte)8 , (byte)2);
      getData( buffer, (byte)(5+8), (byte)16 , (byte)3);
      getData( buffer, (byte)(5+8+16), (byte)5 , (byte)4);
      getData( buffer, (byte)(5*2+8+16), (byte)8 , (byte)5);
      getData( buffer, (byte)(5*2+8*2+16), (byte)16 , (byte)6);
      getData( buffer, (byte)(5*2+8*2+16*2), (byte)5 , (byte)7);

       
       apdu.setOutgoingAndSend((short)0, (short)6);
    }
    private void getData( byte buffer[], byte offset, byte len , byte val) {
      byte cnt;
      for( cnt = offset; cnt < offset + len ; cnt++){
            buffer[cnt] = val;
//         waits();
      }
   }
    private void waits(  ) {
      byte i;
      for( i=0; i<0x20; i++){
      }
   }

}












User avatar
mabel
Posts: 234
Joined: Mon May 18, 2015 3:09 am
Points :1663
Contact:

Re: Testing command success on JCIDE but failed on real card?

Post by mabel » Thu Dec 03, 2015 11:02 pm

Is the communication protocol of your card the same as the simulator protocol in JCIDE?

"6C xx" means you should tell cards the number of returned bytes(xx) you expected.
So you should append Le byte to the APDU command and resend it.
>> 00 B3 00 00 06

Note:
You'd better set the same simulator protocol in JCIDE as the real card.

leonard
Posts: 25
Joined: Wed Nov 18, 2015 12:13 am
Points :176
Contact:

Re: Testing command success on JCIDE but failed on real card?

Post by leonard » Fri Dec 04, 2015 4:59 am

mabel wrote:Is the communication protocol of your card the same as the simulator protocol in JCIDE?

"6C xx" means you should tell cards the number of returned bytes(xx) you expected.
So you should append Le byte to the APDU command and resend it.
>> 00 B3 00 00 06

Note:
You'd better set the same simulator protocol in JCIDE as the real card.

Thanks for your answer,
The problem is solved as your explanation. Issue occur because of different protocol, pyApdutool set protocol is T1 while card support T0 protocol.
I've changed the command by adding Le byte, then its work now.

Post Reply Previous topicNext topic

Who is online

Users browsing this forum: Google [Bot] and 3 guests

JavaCard OS : Disclaimer