Understanding Java Card 2.0

Learn the inner workings of the Java Card architecture, API, and runtime environment

1 2 Page 2
Page 2 of 2

An applet on the card remains inactive until it is explicitly selected. The terminal sends a "SELECT APDU" command to JCRE. JCRE suspends the currently selected applet and invokes the applet's deselect method to perform any necessary cleanup. JCRE then marks the applet whose AID is specified in the "SELECT APDU" command as the currently selected applet and calls the newly selected applet's select method. The select method prepares the applet to accept APDU commands. JCRE dispatches the subsequent APDU commands to the currently selected applet until it receives the next "SELECT APDU" command.

How to write a Java Card applet

The best way to demonstrate how to create a Java Card 2.0 applet is to walk through an example. The following example is an electronic wallet application, which stores electronic cash. The wallet handles read_balance, deposit, and debit APDU commands. Access to the wallet is authenticated by an owner PIN.

The example is formatted in two columns: The left column contains Java code with Java style comments; the right column provides further explanation of the code that it lines up with on the left side.

package bank.purse;

Java Card supports package and identifier name convention as in standard Java

import javacard.framework.*;

import javacardx.framework.*;

 

public class Wallet extends Applet {

  /* constants declaration */

An applet is an instance of a class which extends from javacard.framework.Applet

  // code of CLA byte in the command APDU header

  final static byte Wallet_CLA =(byte)0xB0;

CLA identifies the application

  // codes of INS byte in the command APDU header

  final static byte Deposit = (byte) 0x10;

  final static byte Debit = (byte) 0x20;

  final static byte Balance = (byte) 0x30;

  final static byte Validate = (byte) 0x40;

INS specifies the application instructions

  // maximum number of incorrect tries before the PIN is blocked

  final static byte PinTryLimit =(byte)0x03;

  // maximum size PIN

  final static byte MaxPinSize =(byte)0x04;

PIN object parameters

  // status word (SW1-SW2) to signal that the balance becomes negative;

  final static short SW_NEGATIVE_BALANCE = (short) 0x6910;

Applet specific static word

  /* instance variables declaration */

  OwnerPIN pin;

  byte balance;

  byte buffer[];

// APDU buffer

 

  private Wallet() {

    // It is good programming practice to allocate

    // all the memory that an applet needs during its

    // lifetime inside the constructor

    pin = new OwnerPIN(PinTryLimit, MaxPinSize);

    balance = 0;

    register();

  } // end of the constructor

private constructor -- an instance of class Wallet is instantiated by its method

Applet registers itself with JCRE by calling method, which is defined in class . Now the applet is visible to the outside world

  public static void install(APDU apdu){

    // create a Wallet applet instance

    new Wallet();

  } // end of method

Method is invoked by JCRE as the last step in the applet installation process

    public boolean select() {

    // reset validation flag in the PIN object to false

    pin.reset();

    // returns true to JCRE to indicate that the applet

    // is ready to accept incoming APDUs.

    return true;

  }// end of method

This method is called by JCRE to inform that this applet has been selected. It performs necessary initialization which is required to process the following APDU messages.

  public void process(APDU apdu) {

    // APDU object carries a byte array (buffer) to

    // transfer incoming and outgoing APDU header

    // and data bytes between card and CAD

    buffer = apdu.getBuffer();

After the applet is successfully selected, JCRE dispatches incoming APDUs to this method.

APDU object is owned and maintained by JCRE. It encapsulates details of the underlying transmission protocol (T0 or T1 as specified in ISO 7816-3) by providing a common interface.

    // verify that if the applet can accept this

    // APDU message

    if (buffer[ISO.OFFSET_CLA] !== Wallet_CLA)

      ISOException.throwIt

           (ISO.SW_CLA_NOT_SUPPORTED);

When an error occurs, the applet may decide to terminate the process and throw an exception containing status word (SW1 SW2) to indicate the processing state of the card.

An exception that is not caught by an applet is caught by JCRE.

    switch (buffer[ISO.OFFSET_INS]) {

      case Balance:   getBalance(apdu); return;

      case Debit:   debit(apdu); return;

      case Deposit:   deposit(apdu);return;

      case Validate:    validate(apdu);return

      default:   ISOException.throwIt

             (ISO.SW_INS_NOT_SUPPORTED);

    }

}   // end of method

The main function of method is to perform an action as specified in APDU and returns an appropriate response to the terminal.

INS byte specifies the type of action needs to be performed

  private void deposit(APDU apdu) {

    // access authentication

    if ( ! pin.isValidated() )

      ISOException.throwIt (ISO.SW_PIN_REQUIRED);

    // Lc byte denotes the number of bytes in the data

    // field of the comamnd APDU

    byte numBytes = (byte) (buffer[ISO.OFFSET_LC]);

    // indicate that this APDU has incoming data and

    // receive data starting from the offset

    // ISO.OFFSET_CDATA

    byte byteRead = (byte)(apdu.setIncomingAndReceive());

    // it is an error if the number of data bytes read does not

    // match the number in Lc byte

    if (byteRead != 1)

      ISOException.throwIt(ISO.SW_WRONG_LENGTh);

    // increase the balance by the amount specified in the

    // data field of the command APDU.

    balance = (byte)

      (balance + buffer[ISO.OFFSET_CDATA]);

    // return successfully

    return;

} // end of deposit method

The parameter APDU object contains a data field, which specifies the amount to be added onto the balance.

Upon receiving the APDU object from JCRE, the first 5 bytes (CLA, INS, P1, P2, Lc/Le) are available in the APDU buffer. Their offsets in the APDU buffer are specified in the class ISO. Because the data field is optional, the applet needs to explicitly inform JCRE to retrieve additional data bytes.

The communication between card and CAD is exchanged between command APDU and response APDU pair. In the deposit case, the response APDU contains no data field. JCRE would take the status word 0x9000 (normal processing) to form the correct response APDU. Applet developers do not need to concern the details of constructing the proper response APDU.

When JCRE catches an Exception, which signals an error during processing the command, JCRE would use the status word contained in the Exception to construct the response APDU.

  private void debit(APDU apdu) {

    // access authentication

    if ( ! pin.isValidated() )

      ISOException.throwIt(ISO.SW_PIN_REQUIRED);

    byte numBytes = (byte)(buffer[ISO.OFFSET_LC]);

    byte byteRead = (byte)(apdu.setIncomingAndReceive());

    if (byteRead != 1)

      ISOException.throwIt(ISO.SW_WRONG_LENGTH);

    // balance can not be negative

    if ( ( balance - buffer[ISO.OFFSET_CDATA]) < 0 )

      ISOException.throwIt(SW_NEGATIVE_BALANCE);

    balance = (byte)

        (balance - buffer[ISO.OFFSET_CDATA]);

} // end of method

In method, The APDU object contains a data field, which specifies the amount to be decrement from the balance

  private void getBalance(APDU apdu) {

    // access authentication

    if ( ! pin.isValidated() )

      ISOException.throwIt(ISO.SW_PIN_REQUIRED);

    // inform system that the applet has finished processing

    // the command and the system should now prepare to

    // construct a response APDU which contains data field

    apdu.setOutgoing();

    // indicate the number of bytes in the data field

    apdu.setOutgoingLength((byte)1);

    // move the data into the APDU buffer starting at offset 0

    buffer[0] = balance;

    // send 1 byte of data at offset 0 in the APDU buffer

    apdu.sendBytes((short)0, (short)1);

} // end of method

returns the Wallet?s balance in the data field of the response APDU.

Because the data field in response APDU is optional, the applet needs to explicitly inform JCRE of the additional data. JCRE uses the data array in the APDU object buffer and the proper status word to construct a complete response APDU.

private void validate(APDU apdu) {

    // retrieve the PIN data which requires to be valid ated

    // the user interface data is stored in the data field of the APDU

    byte byteRead = (byte)(apdu.setIncomingAndReceive());

    // validate user interface and set the validation flag in the user interface

    // object to be true if the validation succeeds.

    // if user interface validation fails, PinException would be

    // thrown from method.

    pin.check(buffer, ISO.OFFSET_CDATA, byteRead);

  } // end of method

} // end of class Wallet

PIN is a method commonly used in smart cards to protect data from unauthorized access

A PIN records the number of unsuccessful tries since the last correct PIN verification. The card would be blocked, if the number of unsuccessful tries exceeds the maximum number of allowed tries defined in the PIN.

After the applet is successfully selected, PIN needs to be validated first, before any other instruction can be performed on the applet.

Conclusion

This article first reviews some fundamental concepts of smart cards, and then explains Java Card 2.0 internals and shows you how to develop a Java Card application.

A Java Card applet is compiled using a regular Java compiler. The output of the compiler (a class file) is input into a Java Card converter which enforces Java Card 2.0 subset compliance, performs name resolution and initial address linking, and optimizes the Java byte code to be suitably running on a Java Card VM. The output of the converter can then be downloaded onto a Java Card. The details of the converter and applet installation protocols aren't discussed in this article because they haven't yet been standardized. We hope to cover these areas in future article.

The Java Card adds a new platform to the world of Java. Widespread adoption and deployment of the Java Card will require marketing promotion, more applications and tools development, and time. At the same time, the number of Java Cards in existence could easily extend into the millions within the next few years. Which means you may soon be storing your personal information and downloading applications using a little card you carry around in your wallet or purse. :END_BODY

Rinaldo Di Giorgio is a staff engineer in the research department at Sun Microsystems. There he experiments with digital economies. Zhiqun Chen is a Java Card engineer in JavaSoft's consumer transaction group. She is working on the Java Card API and application design and development. She has experience in developing Visa Open Platform card applications and MasterCard Mondex terminal and server applications for Java Electronic Commerce Framework.

Learn more about this topic

  • The first article in the Java Developer series on smart cards is "The smart card primer" http://www.javaworld.com/jw-12-1997/jw-12-javadev.html
  • For Java Card-related business opportunities, see "Giving currency to the Java Card API" http://www.javaworld.com/javaworld/jw-02-1998/jw-02-javacard.html
  • For developing applications based on the Java Card 1.0 API, see "Get a jumpstart on the Java Card" http://www.javaworld.com/javaworld/jw-02-1998/jw-02-javadev.html
  • Java Card Web site Javasoft http://java.sun.com/products/javacard/
  • Java commerce Web site http://java.sun.com/products/commerce/
  • Many thanks to Joshua Susser, the Java Card technical lead at Javasoft, for reviewing this article and providing technical guidance.
1 2 Page 2
Page 2 of 2