This discussion is archived
11 Replies Latest reply: Mar 1, 2012 4:42 PM by safarmer RSS

Simulation using Eclipse plugin for JCOP tools

Mehmet Newbie
Currently Being Moderated
Dear All,

In search for a simulation environment for java card applet development I tried to use Eclipse plugin for JCOP tools.
The samples which comes with the JCOP tools works fine but when try to debug my applet I receive the error: Wrong Data 6A 80.
Generic JCOP v2.4.1 is selected for Java Card Simulation.

Following is the JCOP Shell screen:

cm- /term "Remote|localhost:8050"
--Opening terminal
/card -a a000000003000000 -c com.ibm.jc.CardManager
resetCard with timeout: 0 (ms)
--Waiting for card...
ATR=3B F8 13 00 00 81 31 FE 45 4A 43 4F 50 76 32 34 ;.....1.EJCOPv24
31 B7 1.
IOCTL().
ATR: T=1, FI=1/DI=3 (93clk/etu), N=0, IFSC=254, BWI=4/CWI=5, Hist="JCOPv241"
=> 00 A4 04 00 08 A0 00 00 00 03 00 00 00 00 ..............
(908058 nsec)
<= 6F 65 84 08 A0 00 00 00 03 00 00 00 A5 59 9F 65 oe...........Y.e
01 FF 9F 6E 06 47 91 92 18 00 00 73 4A 06 07 2A ...n.G.....sJ..*
86 48 86 FC 6B 01 60 0C 06 0A 2A 86 48 86 FC 6B .H..k.`...*.H..k
02 02 01 01 63 09 06 07 2A 86 48 86 FC 6B 03 64 ....c...*.H..k.d
0B 06 09 2A 86 48 86 FC 6B 04 02 15 65 0B 06 09 ...*.H..k...e...
2B 85 10 86 48 64 02 01 03 66 0C 06 0A 2B 06 01 +...Hd...f...+..
04 01 2A 02 6E 01 02 90 00 ..*.n....
Status: No Error
cm> set-key 255/1/DES-ECB/404142434445464748494a4b4c4d4e4f 255/2/DES-ECB/404142434445464748494a4b4c4d4e4f 255/3/DES-ECB/404142434445464748494a4b4c4d4e4f
cm> init-update 255
=> 80 50 00 00 08 B1 04 15 2B 41 3F 62 AB 00 .P......+A?b..
(2668 usec)
<= 00 00 F9 02 71 E3 BB AD BD CD FF 02 00 00 3D 02 ....q.........=.
9C 31 C7 89 AD 44 8E 13 17 15 2E 5A 90 00 .1...D.....Z..
Status: No Error
cm> ext-auth plain
=> 84 82 00 00 10 CE 6C DC D2 8C BE 5E 33 EC 58 D0 ......l....^3.X.
57 3A 52 D2 24 W:R.$
(2288 usec)
<= 90 00 ..
Status: No Error
cm> delete -r a00000006203010c04
=> 80 E4 00 80 0B 4F 09 A0 00 00 00 62 03 01 0C 04 .....O.....b....
00 .
(1084 usec)
<= 6A 88 j.
Status: Reference data not found
jcshell: Error code: 6a88 (Reference data not found)
jcshell: Wrong response APDU: 6A88
Ignoring expected error
cm> upload -d -b 250 "D:\JCOP\eclipse\projects\DigitalTachograph\bin\digitaltachograph\javacard\digitaltachograph.cap"
=> 80 E6 02 00 16 09 A0 00 00 00 62 03 01 0C 04 08 ..........b.....
A0 00 00 00 03 00 00 00 00 00 00 00 ............
(2100 usec)
<= 00 90 00 ...
Status: No Error
=> 80 E8 00 00 FA C4 82 84 42 01 00 25 DE CA FF ED ........B..%....
02 02 04 00 01 09 A0 00 00 00 62 03 01 0C 04 11 ..........b.....
64 69 67 69 74 61 6C 74 61 63 68 6F 67 72 61 70 digitaltachograp
68 02 00 21 00 25 00 21 00 0E 00 29 03 3E 00 CD h..!.%.!...).>..
23 D2 01 BB 04 44 00 00 09 E3 4B E5 00 11 00 05 #....D....K.....
01 A2 04 01 00 04 00 29 04 00 01 07 A0 00 00 00 .......)........
62 00 01 02 01 07 A0 00 00 00 62 01 01 02 01 07 b.........b.....
A0 00 00 00 62 01 02 02 01 07 A0 00 00 00 62 02 ....b.........b.
01 03 00 0E 01 0A A0 00 00 00 62 03 01 0C 04 01 ..........b.....
01 DF 06 00 CD 00 00 00 80 00 00 FF 00 01 00 00 ................
00 01 81 03 13 00 12 07 03 00 00 02 01 03 06 0B ................
8C 81 00 00 00 80 00 0B 00 0B 01 01 00 00 0B F9 ................
00 80 00 11 00 0F 01 01 00 10 0E A9 0D D4 0D F7 ................
0E 07 0E 18 0E 26 0E 35 0E 44 0E 50 0E 72 0E 81 .....&.5.D.P.r..
0E 90 0E 9B 0E F5 11 05 11 1A 11 50 00 80 00 05 ...........P....
00 04 01 04 00 01 13 AF 13 B5 13 BA 14 0C 13 00 ................
(6775 usec)
<= 6A 80 j.
Status: Wrong data
jcshell: Error code: 6a80 (Wrong data)
jcshell: Wrong response APDU: 6A80
Unexpected error; aborting execution


I will be very happy if you can help me. I am desperately in need of a working debugging environment.
Thanks in advance!

Kind regards,

Mehmet
  • 1. Re: Simulation using Eclipse plugin for JCOP tools
    Umer Journeyer
    Currently Being Moderated
    Hi,

    Please share your applet code. After seeing code it it will be easy to figure out what is going wrong.
    And also please use
     tages for placing the trace or code as it will be more readable.
    
    Regards                                                                                                                                                                                                                                                                                                                                                                                                                                            
  • 2. Re: Simulation using Eclipse plugin for JCOP tools
    Mehmet Newbie
    Currently Being Moderated
    Following is the code of the main class which can be loaded to gemXpressoPro card using NetBeans IDE. JC SDK v. 2.2.1 is used..
    mode_201
    gemXpressoPro
    enable_trace
    establish_context
    card_connect
    select -AID A000000018434D00
    
    open_sc -security 3 -keyind 0 -keyver 0 -key 47454d5850524553534f53414d504c45
    
    delete -AID a00000006203010c0401
    delete -AID a00000006203010c04
    install -file build/classes/digitaltachograph/javacard/digitaltachograph.cap -priv 4 -sdAID A000000018434D00 -nvCodeLimit 4000
    select -AID a00000006203010c04
    
    card_disconnect
    release_context
  • 3. Re: Simulation using Eclipse plugin for JCOP tools
    Mehmet Newbie
    Currently Being Moderated
    /*
     * To change this template, choose Tools | Templates
     * and open the template in the editor.
     */
    package digitaltachograph;
    
    import javacard.framework.APDU;
    import javacard.framework.Applet;
    import javacard.framework.CardRuntimeException;
    
    import javacard.framework.ISO7816;
    import javacard.framework.ISOException;
    import javacard.framework.JCSystem;
    import javacard.framework.OwnerPIN;
    import javacard.framework.Util;
    import javacard.security.CryptoException;
    import javacard.security.RandomData;
    import javacard.security.Signature;
    import javacardx.crypto.Cipher;
    
    /**
     *
     * @author colakme
     */
    public class DigitalTachograph extends Applet implements ISO7816 {
    
        static byte volatileState[];
        static byte persistentState;
    
        /* values for volatile state */
        static final byte CHALLENGED = 1;
        static final byte MUTUAL_AUTHENTICATED = 2; // ie BAC
        static final byte FILE_SELECTED = 4;
        static final byte CHIP_AUTHENTICATED = 0x10;
        static final byte TERMINAL_AUTHENTICATED = 0x20;
        /* persistent state */
        static final byte LOCKED = 4;
    
        /* values for Access conditions */
        static final byte READ_ALW = 1;
        static final byte READ_REQUIRES_SM = 2;
        static final byte UPDATE_ALW = 4;
        static final byte UPDATE_REQUIRES_SM = 8;
        static final byte ENCRYPTED = 0x10;
        /* PIN Verification*/
        // maximum number of incorrect tries before the PIN is blocked
        final static byte PIN_TRY_LIMIT = (byte) 0x03;
        final static byte MAX_PIN_SIZE = (byte) 0x08;  // maximum size PIN
        // signal that the PIN verification failed
        final static short SW_VERIFICATION_FAILED = 0x6300;
        // signal the the PIN validation is required
        final static short SW_PIN_VERIFICATION_REQUIRED = 0x6301;
    
        /* for authentication */
        static final byte CLA_PROTECTED_APDU = 0x0c;
        static final byte INS_INTERNAL_AUTHENTICATE = (byte) 0x88;
        static final byte INS_EXTERNAL_AUTHENTICATE = (byte) 0x82;
    
        /* for EAC */
        final static byte INS_VERIFY = (byte) 0x20;
        static final byte INS_GET_CHALLENGE = (byte) 0x84;
        static final byte INS_SELECT_FILE = (byte) 0xA4;
        static final byte INS_READ_BINARY = (byte) 0xB0;
        static final byte INS_TEST = (byte) 0xB2;
        static final byte INS_TEST1 = (byte) 0xB3;
        static final byte INS_TEST2 = (byte) 0xB4;
        static final byte INS_TEST3 = (byte) 0xB5;
    
        static final byte INS_Return_PRnd4 = (byte) 0xB6;
        static final byte INS_Return_K2 = (byte) 0xB7;
        static final byte INS_Return_rnd3 = (byte) 0xB8;
        static final byte INS_Return_Card_Chr = (byte) 0xB9;
        static final byte INS_Return_PreDigest = (byte) 0xA0;
        
        static final byte INS_PSO = (byte) 0x2A;
        static final byte INS_MSE = (byte) 0x22;
        static final byte P2_VERIFYCERT = (byte) 0xAE;
        static final byte P1_SETFORCOMPUTATION = (byte) 0x41;
        static final byte P1_SETFORVERIFICATION = (byte) 0x81;
        static final byte P2_KAT = (byte) 0xA6;
        static final byte P2_DST = (byte) 0xB6;
        static final byte P2_AT = (byte) 0xA4;
    
        /* for writing */
        static final byte INS_UPDATE_BINARY = (byte) 0xd6;
        static final byte INS_CREATE_FILE = (byte) 0xe0;
        static final byte INS_PUT_DATA = (byte) 0xda;
        /* status words */
        private static final short SW_OK = (short) 0x9000;
        private static final short SW_REFERENCE_DATA_NOT_FOUND = (short) 0x6A88;
        private static final short SW_CERT_VERIFICATION_FAILED = (short) 0x6688;
        private static final short SW_TAMAM = (short) 0x1234;
        private static final short SW_TAMAM_DEGIL = (short) 0x4321;
        private static final short SW_SECURE_MESSAGING_DATA_OBJECTS_MISSING = (short) 0x6987;
        private static final short SW_SECURE_MESSAGING_NOT_SUPPORTED = (short) 0x6882;
        private static final short SW_INCORRECT_DATA_OBJECT = (short) 0x6988;
        static final short SW_SM_DO_INCORRECT = (short) 0x6988;
        static final short SW_SM_DO_MISSING = (short) 0x6987;
        static final short SW_INTERNAL_ERROR = (short) 0x6d66;
        private DTFileSystem fileSystem;
        private DTFile selectedFile;
    
        byte[] cert;
        private static byte[] TACHOGRAPH_AID = {(byte) 0xFF, (byte) 0x54, (byte) 0x41, (byte) 0x43, (byte) 0x48, (byte) 0x4F};
        private final byte TACHO_AID_LENGTH = 0x06;
        private static final short TACHO_CERT_LENGTH = 194;
        private static final short KID_LENGTH = 8;
        KeyStore keyStore;
        byte[] pinValue = {(byte) 0x31, (byte) 0x32, (byte) 0x33, (byte) 0x34, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF};
        OwnerPIN pin;
        private byte[] K1;
        private byte[] K2;
        private byte[] KaKb;
        private byte[] SSC;
        private byte[] Rnd1;
        private byte[] Rnd3;
        private byte[] PRnd2;
        RandomData random;
        DTCrypto crypto;
        byte[] digest;
        byte[] preDigest;
        byte[] signed;
    
        public DigitalTachograph(byte[] bArray, short bOffset, byte bLength) {
            pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
            pin.update(pinValue, (short) 0, (byte) pinValue.length);
            fileSystem = new DTFileSystem();
            selectedFile = fileSystem.getMF();
    
            keyStore = new KeyStore();
            crypto = new DTCrypto(keyStore);
    
    
            volatileState = JCSystem.makeTransientByteArray((byte) 1, JCSystem.CLEAR_ON_RESET);
            cert = JCSystem.makeTransientByteArray((short) TACHO_CERT_LENGTH, JCSystem.CLEAR_ON_RESET);
            //cert = new byte [TACHO_CERT_LENGTH];
    
            K1 = JCSystem.makeTransientByteArray((short) 16, JCSystem.CLEAR_ON_RESET);
            K2 = JCSystem.makeTransientByteArray((short) 16, JCSystem.CLEAR_ON_RESET);
            KaKb = JCSystem.makeTransientByteArray((short) 16, JCSystem.CLEAR_ON_RESET);
            SSC = JCSystem.makeTransientByteArray((short) 8, JCSystem.CLEAR_ON_RESET);
    
            Rnd1 = JCSystem.makeTransientByteArray((short) 8, JCSystem.CLEAR_ON_RESET);
            Rnd3 = JCSystem.makeTransientByteArray((short) 8, JCSystem.CLEAR_ON_RESET);
            PRnd2 = JCSystem.makeTransientByteArray((short) 90, JCSystem.CLEAR_ON_RESET);
            digest = JCSystem.makeTransientByteArray((short) 20, JCSystem.CLEAR_ON_RESET);
            signed = JCSystem.makeTransientByteArray((short) 128, JCSystem.CLEAR_ON_RESET);
            preDigest = JCSystem.makeTransientByteArray((short) 122, JCSystem.CLEAR_ON_RESET);
            //signed1 = JCSystem.makeTransientByteArray((short) 128, JCSystem.CLEAR_ON_RESET);
            //Aut_Token_VU = JCSystem.makeTransientByteArray((short) 128, JCSystem.CLEAR_ON_RESET);
            random = RandomData.getInstance(RandomData.ALG_SECURE_RANDOM);
        }
    
        private void verifyCardCertificates() {
            selectedFile = fileSystem.getFile(DTFileSystem.EF_CA_Certificate_FID);
            Util.arrayCopyNonAtomic(selectedFile.getData(), (short) 0, cert, (short) 0, TACHO_CERT_LENGTH);
            keyStore.CardCA_Cert.verifyCert(cert, keyStore.eurPublicKey, keyStore.ERCA_KID);
    
            selectedFile = fileSystem.getFile(DTFileSystem.EF_Card_Certificate_FID);
            Util.arrayCopyNonAtomic(selectedFile.getData(), (short) 0, cert, (short) 0, TACHO_CERT_LENGTH);
            keyStore.Card_Cert.verifyCert(cert, keyStore.CardCA_Cert.publicKey, keyStore.CardCA_Cert.CHR);
        }
    
    
        public static void install(byte[] bArray, short bOffset, byte bLength) {
            // GP-compliant JavaCard applet registration
            new DigitalTachograph(bArray, bOffset, bLength).register(bArray, (short) (bOffset + 1), bArray[bOffset]);
    
        }
        private static boolean needLe(byte ins) {
            if(ins == INS_READ_BINARY) {
                return true;
            }
            return false;
        }
        public void process(APDU apdu) {
            byte[] buffer = apdu.getBuffer();
            byte cla = buffer[OFFSET_CLA];
            byte ins = buffer[OFFSET_INS];
            byte p1 = (byte) (buffer[OFFSET_P1] & 0xff);
            byte p2 = (byte) (buffer[OFFSET_P2] & 0xff);
            short sw1sw2 = SW_OK;
            boolean protectedApdu = ((byte) (cla & CLA_PROTECTED_APDU) == CLA_PROTECTED_APDU);
            short responseLength = 0;
    
    
            short le = 0;
    
            /* Ignore APDU that selects this applet... */
            if (selectingApplet()) {
                return;
            }
    
            if (protectedApdu) {
                if (hasMutuallyAuthenticated()) {
                    try {
                        le = crypto.unwrapCommandAPDU(SSC, apdu);
                    } catch (CardRuntimeException e) {
                        sw1sw2 = e.getReason();
                        protectedApdu = false;
                        volatileState[0] &= ~MUTUAL_AUTHENTICATED;
                    }
                } else {
                    ISOException.throwIt(SW_SECURE_MESSAGING_NOT_SUPPORTED);
                }
            }/*else{
    
               if( hasMutuallyAuthenticated() ) {
                   volatileState[0] &= ~MUTUAL_AUTHENTICATED;
                   ISOException.throwIt(ISO7816.SW_CONDITIONS_NOT_SATISFIED);
               }
            }*/
    
    
            if (sw1sw2 == SW_OK) {
                try {
                    if (!protectedApdu && needLe(ins)) {
                        le = apdu.setOutgoing();
                    }
    
                    responseLength = processAPDU(apdu, cla, ins, protectedApdu, le);
                } catch (CardRuntimeException e) {
                    sw1sw2 = e.getReason();
                }
            }
    
            if (protectedApdu && hasMutuallyAuthenticated()) {
                responseLength = crypto.wrapResponseAPDU(SSC, apdu, crypto.getApduBufferOffset(responseLength), responseLength, sw1sw2);
            }
    
            if (responseLength > 0) {
                if (apdu.getCurrentState() != APDU.STATE_OUTGOING) {
                    apdu.setOutgoing();
                }
                if (apdu.getCurrentState() != APDU.STATE_OUTGOING) {
                    apdu.setOutgoing();
                }
                if (apdu.getCurrentState() != APDU.STATE_OUTGOING_LENGTH_KNOWN) {
                    apdu.setOutgoingLength(responseLength);
                }
                apdu.sendBytes((short) 0, responseLength);
            }
    
            if (sw1sw2 != SW_OK) {
                ISOException.throwIt(sw1sw2);
            }
        }
    
        public short processAPDU(APDU apdu, byte cla, byte ins, boolean protectedApdu,  short le) {
            short responseLength = 0;
    
            switch (ins) {
                case INS_SELECT_FILE:
                    processSelectFile(apdu);
                    break;
    
                case INS_READ_BINARY:
                    responseLength = processReadBinary(apdu, protectedApdu, le);
                    break;
    
                case INS_UPDATE_BINARY:
                    processUpdateBinary(apdu, protectedApdu);
                    break;
    
                case INS_PSO:
                    processPSO(apdu);
                    break;
    
                case INS_MSE:
                    processMSE(apdu);
                    break;
    
                case INS_VERIFY:
                    processVerify(apdu);
                    break;
    
                case INS_INTERNAL_AUTHENTICATE:
                    responseLength = processInternalAuthenticate(apdu, protectedApdu);
                    break;
                case INS_GET_CHALLENGE:
                    responseLength = processGetChallenge(apdu, protectedApdu);
                    break;
                case INS_EXTERNAL_AUTHENTICATE:
                    processExternalAuthenticate(apdu);
                    break;
    
                case INS_TEST:
                    responseLength = returnOriginalText(apdu);
                    break;
    
                case INS_TEST3:
                    responseLength = returnDigest(apdu);
                    break;
                case INS_Return_PreDigest:
                    responseLength = returnPreDigest(apdu);
                    break;
                default:
                    ISOException.throwIt(SW_INS_NOT_SUPPORTED);
                    break;
            }
            return responseLength;
        }
  • 4. Re: Simulation using Eclipse plugin for JCOP tools
    Mehmet Newbie
    Currently Being Moderated
            /**
         * Processes incoming READ_BINARY APDUs. Returns data of the currently
         * selected file.
         *
         * @param apdu   where the offset is carried in header bytes p1 and p2.
         * @param le  expected length by terminal
         * @return length of the response APDU
         */
        private short processReadBinary(APDU apdu, boolean protectedApdu,  short leUnprotected) {
    
            if (!hasFileSelected()) {
                ISOException.throwIt(SW_CONDITIONS_NOT_SATISFIED);
            }
    
            byte[] buffer = apdu.getBuffer();
            // retrieve p1p2 from apdu buffer
            byte p1 = buffer[OFFSET_P1];
            byte p2 = buffer[OFFSET_P2];
    
            short offset = Util.makeShort(p1, p2);     // offset encoded in P1/P2, 15 lowest bit
    
            // offset encoded in P1/P2, 15 lowest bit
    
            // check if le != 0 <-- no response expected
            if (leUnprotected == 0) {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
            }
    
            if (selectedFile == null) {
                ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
            }
            if ((selectedFile.getAccessConditions() & READ_REQUIRES_SM) == READ_REQUIRES_SM) {
                if(!protectedApdu)
                   ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
            }
            short fileSize = (short) selectedFile.getFileLength();
            // check offset
            if (offset >= fileSize) {
                ISOException.throwIt(ISO7816.SW_INCORRECT_P1P2);
            }
            // check expected length
            if ((short) (offset + leUnprotected) > fileSize) {
                ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
                //ISOException.throwIt(SW_TAMAM);
            }
    
            short bufferOffset = 0;
            crypto.setEncryptionStatus(isSelectedFileEncrypted());
    
            if (protectedApdu) {
                bufferOffset = crypto.getApduBufferOffsetDT(leUnprotected);
                if(isSelectedFileEncrypted())
                   bufferOffset = crypto.getApduBufferOffset(leUnprotected);
                apdu.setOutgoing();
            }
    
            Util.arrayCopyNonAtomic(selectedFile.getData(), offset, buffer, bufferOffset, leUnprotected);
            return leUnprotected;
        }
    
        /**
         * Processes and UPDATE_BINARY apdu. Writes data in the currently selected
         * file.
         *
         * @param apdu
         *            carries the offset where to write date in header bytes p1 and
         *            p2.
         */
        private void processUpdateBinary(APDU apdu, boolean protectedApdu) {
            if (!hasFileSelected() || isLocked()) {
                ISOException.throwIt(ISO7816.SW_COMMAND_NOT_ALLOWED);
            }
            if ((selectedFile.getAccessConditions() & DigitalTachograph.UPDATE_ALW) != DigitalTachograph.UPDATE_ALW) {
    
                if ((selectedFile.getAccessConditions() & DigitalTachograph.UPDATE_REQUIRES_SM) != DigitalTachograph.UPDATE_REQUIRES_SM) {
                    ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
                    return;
                }else if(!protectedApdu){
                        ISOException.throwIt(ISO7816.SW_SECURITY_STATUS_NOT_SATISFIED);
                }
            }
    
            byte[] buffer = apdu.getBuffer();
            byte p1 = buffer[OFFSET_P1];
            byte p2 = buffer[OFFSET_P2];
            short offset = Util.makeShort(p1, p2);
    
    
            short readCount = (short) (buffer[ISO7816.OFFSET_LC] & 0xff);
            //if (!protectedApdu){
                readCount = apdu.setIncomingAndReceive();
            //}
            while (readCount > 0) {
                selectedFile.writeData(offset, buffer, OFFSET_CDATA, readCount);
                offset += readCount;
                readCount = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
            }
        }
    
        private short processInternalAuthenticate(APDU apdu , boolean protectedApdu) throws CryptoException {
            byte[] buffer = apdu.getBuffer();
            short lc = (short) (buffer[OFFSET_LC] & 0xFF);
            if (lc != (short) (KID_LENGTH * 2)) {
                ISOException.throwIt(SW_WRONG_LENGTH);
            }
            if (apdu.setIncomingAndReceive() != lc) {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
            // Check if VU.CHR maches the one of the selected certificate on the card
            if (Util.arrayCompare(buffer, (short) (OFFSET_CDATA + KID_LENGTH), keyStore.selected_KID, (short) 0, KID_LENGTH) != 0) {
                ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
            }
            if (Util.arrayCopyNonAtomic(buffer, OFFSET_CDATA, Rnd1, (short) 0, (short) 8) != (short) 8) { // Receive Rnd1
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
    
            // Hash(PRnd2||K1||Rnd1||VU.CHR)
            random.generateData(PRnd2, (short) 0, (short) 90);
            random.generateData(K1, (short) 0, (short) 16);
            crypto.shaDigest.update(PRnd2, (short) 0, (short) 90); // PRnd2
            crypto.shaDigest.update(K1, (short) 0, (short) 16); // PRnd2||K1
            crypto.shaDigest.doFinal(buffer, OFFSET_CDATA, lc, digest, (short) 0); //Rnd1||VU.CHR
    
          /*
            BigNumber mod = new BigNumber((short) 128);
            mod.init(keyStore.Card_PubMod, (short) 0, (short) keyStore.Card_PubMod.length, BigNumber.FORMAT_HEX);
            mod.subtract(signed, (short) 0, (short) 128, BigNumber.FORMAT_HEX);
            if (mod.compareTo(signed, (short) 0, (short) 128, BigNumber.FORMAT_HEX) == -1) {
                mod.toBytes(signed, (short) 0, (short) 128, BigNumber.FORMAT_HEX);
            }
             */
    
            // To be added: if the selected private key is considered corrupted, the processing state returned is '6400' or '6581'.
    
            signed[0] = (byte) 0x6A;
            Util.arrayCopyNonAtomic(PRnd2, (short) 0, signed, (short) 1, (short) 90);
            Util.arrayCopyNonAtomic(K1, (short) 0, signed, (short) 91, (short) 16);
            Util.arrayCopyNonAtomic(digest, (short) 0, signed, (short) 107, (short) 20);
            signed[127] = (byte) 0xBC;
    
            if (!keyStore.cardPrivateKey.isInitialized()) {
                CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
            }
            try {
                crypto.rsaSigner.init(keyStore.cardPrivateKey, Signature.MODE_SIGN);
                crypto.rsaSigner.doFinal(signed, (short) 0, (short) 128, signed, (short) 0);
    
            } catch (Exception e) {
                ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
            }
    
    
            if (!keyStore.selectedPublicKey.isInitialized()) {
                CryptoException.throwIt(CryptoException.ILLEGAL_VALUE);
            }
    
            try {
                crypto.rsaCipher.init(keyStore.selectedPublicKey, Cipher.MODE_ENCRYPT);
                crypto.rsaCipher.doFinal(signed, (short) 0, (short) 128, signed, (short) 0);
    
            } catch (Exception e) {
                ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
            }
            apdu.setOutgoing();
            Util.arrayCopyNonAtomic(signed, (short) 0, buffer, (short) 0, (short) 128);
            return (short) signed.length;
        }
        private void processExternalAuthenticate(APDU apdu) {
    
            short equipmentType = 0;
            if (keyStore.Selected_Cert != null) {
                equipmentType = (short) keyStore.Selected_Cert.CHA[6]; // check equipment type
            }
            if (equipmentType != (short) 1 && equipmentType != (short) 2 && equipmentType != (short) 3 && equipmentType != (short) 4 && equipmentType != (short) 6) {
                ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED); // Instead of 6F00 throw a more meaningfull SW in case CHA is not valid.
            }
            if (Util.arrayCompare(keyStore.Selected_Cert.CHA, (short) 0, TACHOGRAPH_AID, (short) 0, (short) 6) != 0) {
                ISOException.throwIt(ISO7816.SW_FUNC_NOT_SUPPORTED);
            }
            byte[] buffer = apdu.getBuffer();
            byte p1 = (byte) (buffer[OFFSET_P1] & 0xff);
            byte p2 = (byte) (buffer[OFFSET_P2] & 0xff);
    
            if (p1 != 0 || p2 != 0) {
                ISOException.throwIt(SW_WRONG_P1P2);
            }
    
            short lc = (short) (buffer[OFFSET_LC] & 0xFF);
            if (lc != (short) (128)) {
                ISOException.throwIt(SW_WRONG_LENGTH);
            }
            if (apdu.setIncomingAndReceive() != lc) {
                ISOException.throwIt(ISO7816.SW_WRONG_DATA);
            }
            Util.arrayCopyNonAtomic(buffer, OFFSET_CDATA, signed, (short) 0, (short) 128); // receive the cryptogram from the VU
    
            // decrypt the encrypted message with the card private key
            try {
                crypto.rsaCipher.init(keyStore.cardPrivateKey, Cipher.MODE_DECRYPT);
                crypto.rsaCipher.doFinal(signed, (short) 0, (short) 128, signed, (short) 0);
            } catch (Exception e) {
                ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
            }
    
    
            // verify the signature with the VU public key
            try {
                crypto.rsaCipher.init(keyStore.selectedPublicKey, Signature.MODE_VERIFY); // Cipher.MODE_ENCRYPT
                crypto.rsaCipher.doFinal(signed, (short) 0, (short) 128, signed, (short) 0);
            } catch (Exception e) {
                ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
            }
    
    
            if (signed[0] != (byte) 0x6A || signed[127] != (byte) 0xBC) {
                ISOException.throwIt(Util.makeShort(signed[0], signed[127]));
            }
    
    
            try {
                verifyCardCertificates();
                Util.arrayCopyNonAtomic(signed, (short) 1, preDigest, (short) 0, (short) 106); // accumulate preDigest
                Util.arrayCopyNonAtomic(Rnd3, (short) 0, preDigest, (short) 106, (short) 8); // accumulate preDigest
                Util.arrayCopyNonAtomic(keyStore.Card_Cert.CHR, (short) 0, preDigest, (short) 114, (short) 8); // accumulate preDigest
    
    
                Util.arrayCopyNonAtomic(signed, (short) 91, K2, (short) 0, (short) 16); // receive K2 value
    
                crypto.shaDigest.update(signed, (short) 1, (short) 106); // PRnd4||K2
                crypto.shaDigest.update(Rnd3, (short) 0, (short) 8); // Rnd3
                crypto.shaDigest.doFinal(keyStore.Card_Cert.CHR, (short) 0, (short) 8, digest, (short) 0); //||Card.CHR
            } catch (Exception e) {
                ISOException.throwIt(SW_TAMAM);
            }
    
            if (Util.arrayCompare(signed, (short) 107, digest, (short) 0, (short) 20) != 0) {
                ISOException.throwIt(SW_TAMAM);
            }
    
            volatileState[0] |= MUTUAL_AUTHENTICATED;
    
            try {
                DTUtil.xor(K1, (short) 0, K2, (short) 0, KaKb, (short) 0, (short) 16);
                Util.arrayCopyNonAtomic(Rnd3, (short) 4, SSC, (short) 0, (short) 4); // tail of Rnd3
                Util.arrayCopyNonAtomic(Rnd1, (short) 4, SSC, (short) 4, (short) 4); // tail of Rnd1
            } catch (Exception e) {
                ISOException.throwIt(SW_TAMAM);
            }
            try {
                keyStore.setKey_Ka(KaKb, (short) 0);
                keyStore.setKey_Kb(KaKb, (short) 8);
                keyStore.setSecureMessagingKeys(KaKb, (short) 0, KaKb, (short) 0);
    
            } catch (Exception e) {
                ISOException.throwIt(SW_TAMAM_DEGIL);
            }
            return;
        }
    
        private short returnPreDigest(APDU apdu) {
            byte[] buffer = apdu.getBuffer();
            apdu.setOutgoing();
            Util.arrayCopyNonAtomic(preDigest, (short) 0, buffer, (short) 0, (short) 122);
            return (short)preDigest.length;
        }
        private short returnDigest(APDU apdu) {
            byte[] buffer = apdu.getBuffer();
            apdu.setOutgoing();
            Util.arrayCopyNonAtomic(digest, (short) 0, buffer, (short) 0, (short) 20);
            return (short)digest.length;
        }
    
    
        private short returnOriginalText(APDU apdu) {
            byte[] buffer = apdu.getBuffer();
            apdu.setOutgoing();
            Util.arrayCopyNonAtomic(signed, (short) 0, buffer, (short) 0, (short) 128);
            return (short)signed.length;
        }
    
        private void processVerify(APDU apdu) { // Verify_CHV(Pin_Ws)
            byte[] buffer = apdu.getBuffer();
            // retrieve the PIN data for validation.
            byte byteRead = (byte) (apdu.setIncomingAndReceive());
    
            // the PIN data is read into the APDU buffer
            // at the offset ISO7816.OFFSET_CDATA the PIN data length = byteRead
    
            if (pin.check(buffer, ISO7816.OFFSET_CDATA, byteRead) == false) {
                ISOException.throwIt(SW_VERIFICATION_FAILED);
            }
            return;
        }
    
        private void processPSO(APDU apdu) { // verify certificate
            byte[] buffer = apdu.getBuffer();
            byte p1 = (byte) (buffer[OFFSET_P1] & 0xff);
            byte p2 = (byte) (buffer[OFFSET_P2] & 0xff);
            short lc = (short) (buffer[ISO7816.OFFSET_LC] & 0xFF);
            if (p1 == (byte) 0x00 && p2 == P2_VERIFYCERT) {
                if (lc != TACHO_CERT_LENGTH) {
                    ISOException.throwIt(SW_WRONG_LENGTH);
                }
                if (apdu.setIncomingAndReceive() != lc) {
                    ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
                }
                try { // copy the certificate to be verified from APDU buffer to cert object
                    Util.arrayCopyNonAtomic(buffer, OFFSET_CDATA, cert, (short) 0, lc);
                } catch (Exception e) {
                    ISOException.throwIt(SW_TAMAM);
                }
                if (Util.arrayCompare(keyStore.selected_KID, (short) 0, keyStore.ERCA_KID, (short) 0, KID_LENGTH) == 0) {
                    keyStore.VUCA_Cert.verifyCert(cert, keyStore.selectedPublicKey, keyStore.selected_KID);
                } else if (Util.arrayCompare(keyStore.selected_KID, (short) 0, keyStore.VUCA_Cert.CHR, (short) 0, KID_LENGTH) == 0) {
                    keyStore.VU_Cert.verifyCert(cert, keyStore.selectedPublicKey, keyStore.selected_KID);
                } else {
                    ISOException.throwIt(SW_CERT_VERIFICATION_FAILED); // Selected keyId, with MSE, is neither ERCA_KID nor VUCA_KID
                }
            } else {
                ISOException.throwIt(SW_CERT_VERIFICATION_FAILED);
            }
    
            return;
        }
    
        private short processGetChallenge(APDU apdu, boolean protectedApdu) {
            byte[] buffer = apdu.getBuffer();
            byte p1 = (byte) (buffer[OFFSET_P1] & 0xff);
            byte p2 = (byte) (buffer[OFFSET_P2] & 0xff);
            if (p1 != 0 || p2 != 0) {
                ISOException.throwIt(SW_WRONG_P1P2);
            }
            random.generateData(Rnd3, (short) 0, (short) 8);
            short Le = apdu.setOutgoing();
            if (Le != (short) 8) {
                ISOException.throwIt(SW_WRONG_LENGTH);
            }
            Util.arrayCopyNonAtomic(Rnd3, (short) 0, buffer, (short) 0, (short) 8);
            return Le;
        }
    
        private void processMSE(APDU apdu) {
            byte[] buffer = apdu.getBuffer();
    
            if (buffer[OFFSET_P1] == (byte) 0xC1 && buffer[OFFSET_P2] == P2_DST) {
                short lc = (short) (buffer[OFFSET_LC] & 0xFF);
                if (lc != (short) (KID_LENGTH + 2)) {
                    ISOException.throwIt(SW_WRONG_LENGTH);
                }
                if (apdu.setIncomingAndReceive() != lc) {
                    ISOException.throwIt(ISO7816.SW_WRONG_DATA);
                }
    
                if (buffer[OFFSET_CDATA] != (byte) 0x83) {//check the tag of the data
                    ISOException.throwIt(SW_SECURE_MESSAGING_DATA_OBJECTS_MISSING);
                } else if (buffer[OFFSET_CDATA + 1] != (byte) 0x08) {
                    ISOException.throwIt(SW_INCORRECT_DATA_OBJECT); // check if the key is already selected one
                } else if (Util.arrayCompare(buffer, (short) (OFFSET_CDATA + 2), keyStore.selected_KID, (short) 0, KID_LENGTH) != 0) {
    
                    if (Util.arrayCompare(buffer, (short) (OFFSET_CDATA + 2), keyStore.ERCA_KID, (short) 0, KID_LENGTH) == 0) {// KID is EUR_KID
                        keyStore.selected_KID = keyStore.ERCA_KID;
                        keyStore.selectedPublicKey = keyStore.eurPublicKey;
                        keyStore.Selected_Cert = null; // ERCA public key is selected
                        return;
                    } else if (Util.arrayCompare(buffer, (short) (OFFSET_CDATA + 2), keyStore.VUCA_Cert.CHR, (short) 0, KID_LENGTH) == 0) {// KID is MSCA_KID
                        keyStore.Selected_Cert = keyStore.VUCA_Cert;
    
                    } else if (Util.arrayCompare(buffer, (short) (OFFSET_CDATA + 2), keyStore.VU_Cert.CHR, (short) 0, KID_LENGTH) == 0) { // KID is VU_KID
                        keyStore.Selected_Cert = keyStore.VU_Cert;
                    } else {
                        ISOException.throwIt(SW_REFERENCE_DATA_NOT_FOUND);
                    }// KID not found
                    keyStore.selectedPublicKey = keyStore.Selected_Cert.publicKey;
                    keyStore.selected_KID = keyStore.Selected_Cert.CHR;
    
                } else { // if the KID is already set, just return
                    return;
                }
            } else {
                ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
            }
        }
    
        private void processSelectFile(APDU apdu) {
    
            byte[] buffer = apdu.getBuffer();
            short lc = (short) (buffer[OFFSET_LC] & 0x00FF);
    
            // retrieve p1p2 from apdu buffer
            byte p1 = buffer[OFFSET_P1];
            byte p2 = buffer[OFFSET_P2];
            short p1p2 = Util.makeShort(p1, p2);
    
            apdu.setIncomingAndReceive();
    
            if (p1 == 4) {
                if (lc == (short) TACHO_AID_LENGTH) {
                    if (Util.arrayCompare(buffer, (short) OFFSET_CDATA, TACHOGRAPH_AID, (short) 0, (short) TACHO_AID_LENGTH) == 0) {
                        selectedFile = fileSystem.getDT();
                        fileSystem.selectDT();
                        volatileState[0] |= FILE_SELECTED;
                        return;
    
                    } else {
                        ISOException.throwIt(ISO7816.SW_WRONG_DATA);
                    }
    
                } else if (lc != 2) {
                    ISOException.throwIt(SW_WRONG_LENGTH);
                }
                short fid = Util.getShort(buffer, OFFSET_CDATA);
                if (fileSystem.getFile(fid) != null) {
                    selectedFile = fileSystem.getDT();
                    fileSystem.selectDT();
                    volatileState[0] |= FILE_SELECTED;
                    return;
                }
    
            } else if (p1 == 2) {
                if (lc != 2) {
                    ISOException.throwIt(SW_WRONG_LENGTH);
                }
                short fid = Util.getShort(buffer, OFFSET_CDATA);
                if (fileSystem.getFile(fid) != null) {
                    selectedFile = fileSystem.getFile(fid);
                    volatileState[0] |= FILE_SELECTED;
                    return;
                }
            } else {
                ISOException.throwIt(ISO7816.SW_WRONG_P1P2);
            }
    
            setNoFileSelected();
            ISOException.throwIt(ISO7816.SW_FILE_NOT_FOUND);
        }
    
    
    
        public static void setNoFileSelected() {
            if (hasFileSelected()) {
                volatileState[0] ^= FILE_SELECTED;
            }
        }
    
        public static boolean hasFileSelected() {
            return (volatileState[0] & FILE_SELECTED) == FILE_SELECTED;
        }
    
        public static boolean hasMutuallyAuthenticated() {
            return (volatileState[0] & MUTUAL_AUTHENTICATED) == MUTUAL_AUTHENTICATED;
        }
    
        static boolean isLocked() {
            return (persistentState & LOCKED) == LOCKED;
        }
        public boolean isSelectedFileEncrypted() {
            return ((selectedFile.getAccessConditions() & DigitalTachograph.ENCRYPTED) == DigitalTachograph.ENCRYPTED);
        }
    }
  • 5. Re: Simulation using Eclipse plugin for JCOP tools
    Mehmet Newbie
    Currently Being Moderated
    One more note; NetBeans 7.1 uses GPShell 1.4.3 to load the CAP file onto the card without problems...
  • 6. Re: Simulation using Eclipse plugin for JCOP tools
    Umer Journeyer
    Currently Being Moderated
    Wow :)

    It is too much code to parse by mind. I think you should debug it and found the problem. Possible problem could be that some variable or object has null value and you are using it. I might be wrong but you should debug it.

    Regards
  • 7. Re: Simulation using Eclipse plugin for JCOP tools
    Mehmet Newbie
    Currently Being Moderated
    Exactly, I should debug it! The problem is, except sending and receiving some test APDUs I don't have a debugging environment. That's why I am trying to run it on JCOP java card simulation. This code actually works fine on the card. It just gives the following error when I try to load it to JCOP's Java Card Simulation environment's Generic JCOP v2.4.1 target.
    Status: Wrong data
    jcshell: Error code: 6a80 (Wrong data)
    jcshell: Wrong response APDU: 6A80
    Unexpected error; aborting execution
  • 8. Re: Simulation using Eclipse plugin for JCOP tools
    860435 Newbie
    Currently Being Moderated
    "Generic JCOP v2.4.1" doesn't simulate SmartMX completely.
    try "JCOP on NXP SmartMX", it should be work ok. good luck!

    simon
  • 9. Re: Simulation using Eclipse plugin for JCOP tools
    Mehmet Newbie
    Currently Being Moderated
    Hi Simon there is a progress after your suggestion. Thanks a lot! You are my hero!
    Although, still there is an error towards the end of loading. I increased the -nvCodeLimit parameter in the script file but still I receive the following error. Will be very happy to hear from you again!
    Load report:
      33862 bytes loaded in 0.4 seconds
      effective code size on card:
          + package AID       9
          + applet AIDs       17
          + classes           208
          + methods           9173
          + statics           470
          + exports           0
         ------------------------------
            overall           9877  bytes
    cm>  install -i a00000006203010c0401 -l -d -q C9#() a00000006203010c04 a00000006203010c0401
     => 80 E6 0C 00 26 09 A0 00 00 00 62 03 01 0C 04 0A    ....&.....b.....
        A0 00 00 00 62 03 01 0C 04 01 0A A0 00 00 00 62    ....b..........b
        03 01 0C 04 01 01 14 02 C9 00 00 00                ............
     (41673 usec)
     <= 6A 84                                              j.
    Status: Not enough memory space in the file
    jcshell: Error code: 6a84 (Not enough memory space in the file)
    jcshell: Wrong response APDU: 6A84
    Unexpected error; aborting execution
  • 10. Re: Simulation using Eclipse plugin for JCOP tools
    Mehmet Newbie
    Currently Being Moderated
    I found my answer on the following thread! Thanks safarmer!
    6a84 Not enough memory space in the file
  • 11. Re: Simulation using Eclipse plugin for JCOP tools
    safarmer Expert
    Currently Being Moderated
    You're welcome :)

    Cheers,
    Shane

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points