This discussion is archived
3 Replies Latest reply: Dec 11, 2012 1:27 AM by Adriaan RSS

Problem with CLA

965207 Newbie
Currently Being Moderated
İ have written an applet that accept values from user and then return that value as a response, but I have got a CLA error

The java card applet code is here
[
package third;

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

public class ThirdApplet extends Applet {

     private static final byte SecondApplet_CLA = (byte) 0xB0;
     private static final byte SecondApplet_INS = (byte) 0x10;

     private static final short CLA_ERROR = (short) 0x47;
     private static final short LENGTH_ERROR = (short) 0x33;

     private ThirdApplet() {

          register();
     }

     public static void install(byte bArray[], short bOffset, byte bLength) {
          new ThirdApplet();
     }

     public void process(APDU apdu) {
          // TODO Auto-generated method stub
          if (selectingApplet())
               return;
          byte[] buffer = apdu.getBuffer();

          byte CLA = (byte) (buffer[ISO7816.OFFSET_CLA] & 0xFF);
          byte INS = (byte) (buffer[ISO7816.OFFSET_INS] & 0xFF);

          if (CLA != SecondApplet_CLA)
               ISOException.throwIt(CLA_ERROR);
          switch (INS) {
          case SecondApplet_INS:
               getData(apdu);
               break;
          default:
               ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED);

          }

     }

     public void getData(APDU apdu) {
          
          byte[] buffer = apdu.getBuffer();
          short len = (short)(buffer[ISO7816.OFFSET_LC] & 0xFF);
          short x = len;
          short readCount = apdu.setIncomingAndReceive();
          while(len > 0){
               len -= readCount;
               readCount = apdu.receiveBytes((short)(buffer[ISO7816.OFFSET_CDATA]));
          }
          apdu.setOutgoingAndSend((short)5, x);
          
     }

}]

And here is the andorid code that i used to access the java card applet

[package sadi.example.android_first;

import android.app.Activity;
import android.os.Bundle;
import android.smartcard.CardException;
import android.smartcard.ICardChannel;
import android.smartcard.SmartcardClient;
import android.smartcard.SmartcardClient.ISmartcardConnectionListener;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

public class FirstUygulama extends Activity {

     /** The AID of the ThirdApplet applet on the smart card. */
     private static final byte[] APPLET_AID = new byte[] { (byte) 0x01, 0x02,
               0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x02 };

     /** Smartcard API handle. */
     SmartcardClient smartcard;

     /** GUI elements on the screen. */
     TextView textview = null;
     ScrollView scrollview = null;
     Button button = null;
     EditText txt = null;

     /**
     * Connection listener object to be called when the service is successfully
     * connected or disconnected. After <code>serviceConnected</code> was
     * called, <code>SmartcardClient</code> object is valid.
     */
     ISmartcardConnectionListener connectionListener = new ISmartcardConnectionListener() {
          public void serviceConnected() {
               /** Enable the button to allow access to the smart card. */
               logText("Smart card service connected\n");
               button.setEnabled(true);
          }

          public void serviceDisconnected() {
               /** Disable the button to omit smart card access. */
               logText("Smart card service disconnected\n");
               button.setEnabled(false);

               /** Paranoia mode on: reconnect if the service was killed. */
               connectToService();
          }
     };

     /**
     * Internal helper method to log messages in the textview and scroll to the
     * bottom.
     */
     private void logText(String message) {
          scrollview.post(new Runnable() {
               public void run() {
                    scrollview.fullScroll(ScrollView.FOCUS_DOWN);
               }

          });
          textview.append(message);
     }

     /**
     * Internal helper method to convert a <code>byte[]</code> to a
     * <code>String</code>.
     */
     private static String bytesToString(byte[] bytes) {
          StringBuffer sb = new StringBuffer();
          for (byte b : bytes) {
               sb.append(String.format("%02x ", b & 0xFF));
          }
          return sb.toString();
     }

     /**
     * Internal helper method to do the Smartcard Service binding.
     */
     private void connectToService() {
          logText("Connecting to smart card service...\n");
          try {
               smartcard = new SmartcardClient(this, connectionListener);
          } catch (SecurityException e) {
               logText("Binding not allowed, uses-permission SMARTCARD?");
          } catch (Exception e) {
               logText("Exception: " + e.getMessage());
          }
     }

     @Override
     /**
     * Override onCreate and create the UI elements programmatically.
     */
     public void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);

          LinearLayout layout = new LinearLayout(this);
          layout.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                    LayoutParams.WRAP_CONTENT));
          layout.setOrientation(LinearLayout.VERTICAL);

          txt = new EditText(this);
          txt.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                    LayoutParams.WRAP_CONTENT));

          button = new Button(this);
          button.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
                    LayoutParams.WRAP_CONTENT));
          button.setText("Click Me");
          button.setEnabled(false);
          button.setOnClickListener(new OnClickListener() {
               public void onClick(View v) {
                    runSample();
               }
          });

          scrollview = new ScrollView(this);

          textview = new TextView(this);
          textview.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
                    LayoutParams.WRAP_CONTENT));
          scrollview.addView(textview);

          layout.addView(txt);
          layout.addView(button);
          layout.addView(scrollview);

          setContentView(layout);

          connectToService();
     }

     @Override
     /**
     * Override onDestroy to cleanup the service binding
     */
     protected void onDestroy() {
          if (smartcard != null) {
               logText("Disconnecting from smart card service\n");
               smartcard.shutdown();
          }
          super.onDestroy();
     }

     /**
     * Internal method for smart card access called by the onClick handler
     */
     private void runSample() {
          logText("\nExecuting runSample()...\n");
          String cardReader = "";
          ICardChannel cardChannel = null;

          logText("List card readers:\n");
          try {
               String[] readers = smartcard.getReaders();
               for (String reader : readers) {
                    logText(" " + reader + "\n");
               }
               if (readers.length > 0) {
                    cardReader = smartcard.getReaders()[0];
               } else {
                    logText("no card reader found on system\n");
                    return;
               }
          } catch (CardException e) {
               logText("CardException: " + e.getMessage());
               return;
          }

          logText("Smart card status:\n");
          try {
               boolean isPresent = smartcard.isCardPresent(cardReader);
               logText(" " + (isPresent ? "present\n" : "absent\n"));
               if (isPresent == false) {
                    return;
               }
          } catch (CardException e) {
               logText("CardException: " + e.getMessage());
               return;
          }

          logText("Smart card communication:\n");
          try {
               cardChannel = smartcard.openLogicalChannel(cardReader, APPLET_AID);
               byte[] cmdApdu1 = new byte[] { (byte) 0xB0, 0x10, 0x00, 0x00, 0x04 };
               
               // Retrieving data from EditText and add them to the cmdApdu array
               String txtValue = txt.getText().toString();
               String value = txtValue.replaceAll("\\s+", "");
               int len = value.length();

               byte[] data = new byte[len / 2];
               for (int i = 0; i < len; i += 2) {
                    data[i / 2] = (byte) ((Character.digit(value.charAt(i), 16) << 4) + Character
                              .digit(value.charAt(i + 1), 16));
               }
               
               // Merging the two arrays in one array
               byte[] cmdApdu = new byte[cmdApdu1.length + data.length];
               System.arraycopy(cmdApdu1, 0, cmdApdu, 0, cmdApdu1.length);
               System.arraycopy(data, 0, cmdApdu, cmdApdu1.length, data.length);
               logText(" ->: " + bytesToString(cmdApdu) + "\n");
               
               //Getting response APDU from the card applet
               byte[] rspApdu = cardChannel.transmit(cmdApdu);
               logText(" <-: " + bytesToString(rspApdu) + "\n");
               byte[] helloStr = new byte[rspApdu.length - 2];
               System.arraycopy(rspApdu, 0, helloStr, 0, rspApdu.length - 2);

               Toast.makeText(FirstUygulama.this, new String(helloStr),
                         Toast.LENGTH_LONG).show();
          } catch (CardException e) {
               logText("CardException: " + e.getMessage());
               return;
          }

          logText("Closing smart card channel\n");
          try {
               cardChannel.close();
          } catch (CardException e) {
               logText("CardException: " + e.getMessage());
               return;
          }
     }

     @Override
     public boolean onCreateOptionsMenu(Menu menu) {
          // Inflate the menu; this adds items to the action bar if it is present.
          getMenuInflater().inflate(R.menu.activity_first_uygulama, menu);
          return true;
     }

}
]

The result i got after running this program is 00 47. But when execute the java card applet alone i have not get any error !!!
  • 1. Re: Problem with CLA
    Umer Journeyer
    Currently Being Moderated
    did you install your applet on a SIM card/real card or simulating it ?
  • 2. Re: Problem with CLA
    965207 Newbie
    Currently Being Moderated
    Yes it is installed on a real SİM card

    Edited by: 962204 on 10.Ara.2012 04:03
  • 3. Re: Problem with CLA
    Adriaan Explorer
    Currently Being Moderated
    I have seen something similar before. The middleware/drivers modify the CLA in transit so it is not the value your applet expects - the modification will depend on the transfer protocol (SWP in your case, I assume).

    The first step should be to check what value is received by your applet. Change your applet to simply return (echo) the entire incoming APDU and proceed from there.

    Also have a look at single wire protocol (SWP) standard ETSI TS 102 613.

    I recommend you read these documents about CLA and logical channels:
    http://askra.de/software/jcdocs/app-notes-2.2.1/logchan.html
    http://martinpaljak.net/download/democard/jc304/classic/jcre_classic/html/selection-jcre-classic.htm

    There is much more info about CLA in the ISO7816-3 and ISO7816-4 specification.


    Hope this helps.

    Adriaan

Legend

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