11 Replies Latest reply: Mar 1, 2012 6:42 PM by safarmer RSS

    Simulation using Eclipse plugin for JCOP tools

    Mehmet
      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
          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
            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
              /*
               * 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
                        /**
                     * 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
                  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
                    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
                      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
                        "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
                          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
                            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
                              You're welcome :)

                              Cheers,
                              Shane