Advertisement: Support JavaWorld, click here!
July 1999
HOME FEATURES COLUMNS NEWS & REVIEWS TIPS Q&A JW RESOURCES ABOUT JW

How to write a Java Card applet: A developer's guide

Learn the programming concepts and major steps of creating Java Card applets

Summary
Java Card technology provides the smallest Java platform for memory-constrained devices like smart cards. Zhiqun Chen provides a step-by-step guide to the programming concepts and APIs programmers should use when developing Java Card applets, wrapping up with an example applet written in Java.

This article is intended for Java programmers who wish to extend their development efforts onto the Java Card platform. It also provides an excellent introduction for programmers experienced in writing software for smart cards, but accustomed to programming in assembler or C. The author assumes a working knowledge of smart card technology and a basic understanding of the Java Card platform. (8,000 words)

By Zhiqun Chen


This article walks you through the process of creating a simple electronic wallet applet and provides directions for building an applet and constructing its code. If you need a refresher on the basics of Java Card technology, refer to the March 1998 Java Developer column, "Understanding Java Card 2.0," which provides an overview of smart cards and describes the system architecture, the APIs, and the runtime environment of the Java Card technology. For consistency, this article uses the same wallet applet example as was used in the March 1998 column. However, the wallet applet we'll use in this article has been updated to reflect changes to the APIs in Java Card 2.1. In addition, while the previous article served as an overall introduction to the Java Card technology, this article focuses on writing applets for Java Card 2.1.

Java Card basics

For the purpose of this article, the term Java Card denotes a Java Card technology-enabled smart card. Java Card technology allows applets written in the Java language to be executed on a smart card. It defines a Java Card Runtime Environment (JCRE) and provides classes and methods to help developers create applets. Applets run within the JCRE. The JCRE and APIs are modeled after the smart card specification ISO 7816.

When a Java Card is inserted into a card acceptance device (CAD), the CAD selects an applet on the card and sends it a series of commands to execute. Each applet is identified and selected by its application identifier (AID). Commands such as the selection command are formatted and transmitted in the form of application protocol data units (APDUs). Applets reply to each APDU command with a status word (SW) that indicates the result of the operation. An applet can optionally reply to an APDU command with other data.

Architect the applet
As with any software application development, before sitting down and writing a Java Card applet, you should first go through a design phase. In this phase, you define the architecture of the applet.

Four steps comprise the applet-design phase:

  1. Specify the functions of the applet
  2. Request and assign AIDs to both the applet and the package containing the applet class
  3. Design the class structure of the applet programs
  4. Define the interface between the applet and the terminal application

In the following sections, we'll use the example of a wallet applet to take a detailed look at each of the steps in the applet-design process.

Specifying the functions of the applet
Our example wallet applet will store electronic money and support credit, debit, and check-balance functions.

To help prevent unauthorized use of the card, it contains a security algorithm. This algorithm requires the user to enter a PIN, a string of eight digits at most. The card user types his or her PIN on a keypad connected to the CAD. The security algorithm causes the card to lock after three unsuccessful attempts to enter the PIN. The PIN is initialized according to the installation parameters when the applet is installed and created.

The PIN must be verified before any credit or debit transaction can be executed.

For simplicity, let's say the card's maximum balance is $32,767, and that no credit or debit transaction can exceed $127. Thus, Java variables of type short and byte can represent the wallet balance and the amount of each transaction, respectively.

*A real-world wallet applet would require a much more sophisticated security mechanism to prevent unauthorized access to the wallet.

Specifying AIDs
Most applications with which you are familiar are named and identified by a string name. In Java Card technology, however, each applet is identified and selected by an AID. Also, each Java package is assigned an AID. This is because a package, when loaded on a card, is linked with other packages, which have already been placed on the card via their AIDs. This naming convention is in conformance with the smart card specification as defined in ISO 7816.

An AID is a sequence of bytes between 5 and 16 bytes in length. Its format is depicted in Table 1.

Application identifier (AID)

National registered application provider (RID)

Proprietary application identifier extension (PIX)

5 bytes

0 to 11 bytes

Table 1. AID format

ISO controls the assignment of RIDs to companies, with each company obtaining its own unique RID from the ISO. Companies manage assignment of PIXs for AIDs.

The Java classes of the wallet applet are defined in a Java package. The fictitious AIDs for the wallet applet and the applet package are defined as illustrated in Table 2.

Package AID
Field Value Length
RID 0xF2, 0x34, 0x12, 0x34, 0x56 5 bytes
PIX 0x10, 0x00, 0x00 3 bytes
Applet AID
Field Value Length
RID 0xF2, 0x34, 0x12, 0x34, 0x56 5 bytes
PIX 0x10, 0x00, 0x01 3 bytes
Table 2. Fictitious AIDs for the wallet applet and the applet package

The package AID and the applet AID have the same RID value; their PIX values differ at the last bit.

Defining the class structure and method functions of the applet
A Java Card applet class must extend from the javacard.framework.Applet class. This class is the superclass for all applets residing on a Java Card. It defines the common methods an applet must support in order to interact with the JCRE during its lifetime.

Table 3 lists the public and protected methods defined in the class javacard.framework.Applet:

Method summary
public void deselect ()

Called by the JCRE to inform the currently selected applet that another (or the same) applet will be selected.
public Shareable getShareableInterfaceObject (AID client AID, byte parameter)

Called by the JCRE to obtain a sharable interface object from this server applet on behalf of a request from a client applet.
public static void install (byte[] bArray, short bOffset, byte bLength)

The JCRE calls this static method to create an instance of the Applet subclass.
public abstract void process (APDU apdu)

Called by the JCRE to process an incoming APDU command.
protected final void register ()

This method is used by the applet to register this applet instance with the JCRE and assign the default AID in the CAD file to the applet instance.
protected final void register (byte[] bArray, short bOffset, byte bLength)

This method is used by the applet to register this applet instance with the JCRE and to assign the specified AID in the array bArray to the applet instance.
public boolean select ()

Called by the JCRE to inform this applet that it has been selected.
protected final boolean selectingApplet ()

This method is used by the applet process() method to distinguish the SELECT APDU command that selected this applet from all other SELECT APDU APDU commands that may relate to file or internal applet state selection.
Table 3. Public and protected methods defined in the class javacard.framework.Applet

The class javacard.framework.Applet provides a framework for applet execution. Methods defined in this class are called by the JCRE when the JCRE receives APDU commands from the CAD.

After the applet code has been properly loaded on a Java Card and linked with other packages on the card, an applet's life starts when an applet instance is created and registered with the JCRE's registry table. An applet must implement the static method install() to create an applet instance and register the instance with the JCRE by invoking one of the two register() methods. The install()method takes a byte array as a parameter. This array contains the installation parameters for initializing or personalizing the applet instance.

An applet on a Java Card is in an inactive stage until it is explicitly selected. When the JCRE receives a SELECT APDU command, it searches its internal table for the applet whose AID matches the one specified in the command. If a match is found, the JCRE prepares the new applet to be selected. This preparation process consists of two steps: First, if a currently-selected applet is present, the JCRE deselects it by invoking the deselect() method. The applet performs any clean-up or bookkeeping work in the deselect() method before it goes into the inactive stage. Then the JCRE invokes the select() method to inform the new applet that it has been selected. The new applet performs any initialization necessary before it actually becomes selected. The applet returns true to the select() method if it is now ready to become active and to process subsequent APDU commands. Otherwise, the applet returns false to decline its participation, and if so, no applet will be selected. The javacard.framework.Applet class provides a default implementation for both the select() and deselect() methods. A subclass of the Applet class may override these two methods to define the applet's behavior during selection and deselection.

Once an applet is selected, the JCRE forwards all subsequent APDU commands (including the SELECT command) to the applet's process() method. In the process() method, the applet interprets each APDU command and performs the task specified by the command. For each command APDU, the applet responds to the CAD by sending back a response APDU, which informs the CAD of the result of processing the command APDU. The process() method in class javacard.framework.Applet is an abstract method: a subclass of the Applet class must override this method to implement an applet's functions.

This command-and-response dialogue continues until a new applet is selected or the card is removed from the CAD. When deselected, an applet becomes inactive until the next time it is selected.

The getShareableInterfaceObject method is intended for interapplet communication. It is invoked by a client applet to request a sharable interface object from the server applet. The default implementation of this method returns null. Unfortunately, a detailed discussion of object sharing and interapplet communication would be beyond the scope of this article.

Since the SELECT APDU command is also forwarded to the process() method, the selectingApplet() method is used by the applet's process() method to distinguish the SELECT APDU command selecting this applet from all other SELECT APDU commands that may relate to file or internal applet state selection.

Defining the interface between an applet and its terminal application
An applet running in a smart card communicates with the terminal application at the CAD using application protocol data units. In essence, the interface between an applet and its terminal application is a set of APDU commands that are agreed upon and supported by both the applet and the terminal application.

An APDU primer
This section provides a summary of APDU commands to get you started defining APDU commands for the wallet applet. (The details of the APDU protocol are specified in ISO 7816.)

APDU commands are always sets of pairs. Each pair contains a command APDU, which specifies a command, and a response APDU, which sends back the execution result of the command. In the card world, smart cards are reactive communicators -- that is, they never initiate communications, they only respond to APDUs from the outside world. The terminal application sends a command APDU through the CAD. The JCRE receives the command, and either selects a new applet or passes the command to the currently selected applet. The currently selected applet processes the command and returns a response APDU to the terminal application. Command APDUs and response APDUs are exchanged alternately between a card and a CAD.

Table 4 describes command and response APDU formats.

Command APDU

Mandatory header Optional body
CLA INS P1 P2 Lc Data field Le
  • CLA (1 byte): Class of instruction --- indicates the structure and format for a category of command and response APDUs
  • INS (1 byte): Instruction code: specifies the instruction of the command
  • P1 (1 byte) and P2 (1 byte): Instruction parameters -- further provide qualifications to the instruction
  • Lc (1 byte): Number of bytes present in the data field of the command
  • Data field (bytes equal to the value of Lc): A sequence of bytes in the data field of the command
  • Le (1 byte): Maximum of bytes expected in the data field of the response to the command

Response APDU

Optional body Mandatory trailer
Data field SW1 SW2
  • Data field (variable length): A sequence of bytes received in the data field of the response
  • SW1 (1 byte) and SW2 (1 byte): Status words -- denote the processing state in the card
Table 4. Command and response APDU formats

Defining APDU commands
A Java Card applet should support a set of APDU commands, comprising a SELECT APDU command and one or more process APDU commands.

Java Card technology specifies the encoding of the SELECT APDU command. Applet developers are free to define the encoding of their process commands. However, process commands must comply with the structure outlined above.

Structurally, the SELECT command and process commands are pairs of command and response APDUs.

For each command APDU, the applet should first decode the value of each field in the command. If the optional data fields are included, the applet should also determine their format and the structure. Using these definitions, the applet knows how to interpret each command and read the data. It then can execute the task specified by the command.

For each response APDU, the applet should define a set of status words to indicate the result of processing the paired-command APDU. During normal processing, the applet returns the success status word (0x9000, as specified in ISO 7816). If an error occurs, the applet must return a status word other than 0x9000 to denote its internal state. If the optional data field is included in the response APDU, the applet should define what to return.

In the wallet applet example, the applet supports credit, debit, and check-balance functions. In addition, it must support the VERIFY command for PIN verification.

The SELECT command and four process APDU commands for the wallet applet are defined as illustrated in Table 5.

SELECT APDU command

Command APDU

CLA INS P1 P2 Lc Data field Le
0x0 0xA4 0x04 0x0 0x08 0xF2, 0x34, 0x12, 0x34, 0x56, 0x10, 0x0, 0x1 N/A
The command header (CLA, INS, P1, and P2) must be coded as in the above table, so that the JCRE can identify it as a SELECT APDU command. The data field contains the AID of the wallet applet. The JCRE searches its internal registry table against the AID bytes. If a match is found, the wallet applet is selected.

Response APDU

Optional data Status word Meaning of status word
No data 0x9000 Successful processing
  0x6999 Applet selection failed: the applet could not be found or selected
VERIFY APDU command

Command APDU

CLA INS P1 P2 Lc Data field Le
0xB0 0x20 0x0 0x0 Length of the PIN data PIN data N/A
  • CLA byte denotes the structure of the command
  • INS byte (0x20) indicates a verify instruction
  • P1 and P2 are not used, and are both set to 0
  • The data field contains the PIN value
Optional data Status word Meaning of status word
N/A 0x9000 Successful processing
  0x6300 Verification failed
CREDIT APDU command

Command APDU

CLA INS P1 P2 Lc Data field Le
0xB0 0x30 0x0 0x0 1 Credit amount N/A
  • The data field contains the credit amount

Response APDU

Optional data Status word Meaning of status word
N/A 0x9000 Successful processing
0x6301 PIN verification required
0x6A83 Invalid credit amount
0x6A84 Exceed the maximum amount
DEBIT APDU command

Command APDU

CLA INS P1 P2 Lc Data field Le
0xB0 0x40 0x0 0x0 1 Debit amount N/A
  • The data field contains the debit amount

Response APDU

Optional data Status word Meaning of status word
N/A 0x9000 Successful processing
0x6301 PIN verification required
0x6A83 Invalid debit amount
0x6A85 Negative balance
GET BALANCE APDU command

Command APDU

CLA INS P1 P2 Lc Data field Le
0xB0 0x50 0x0 0x0 N/A N/A 2
  • The data field contains the balance amount

Response APDU

Optional data Status word Meaning of status word
N/A 0x9000 Successful processing

Table 5. APDU commands for the wallet applet

In addition to the status words declared in each response APDU command, the interface javacard.framework.ISO7816 defines a set of status words that signal common errors in applets, such as an APDU command formatting error.

APDU support in Java Card technology
The class javacard.framework.APDU encapsulates APDU commands. It provides a powerful and flexible interface to allow applets to handle APDU commands. The APDU class is designed to hide the intricacies of the protocol, so applet developers can concentrate on the details of the application.

When the JCRE receives an APDU command, it encapsulates the command as an APDU object and passes the APDU object to the process() method of the currently selected applet. The APDU object carries a byte array, which contains the APDU message content.

The applet processes an APDU command by invoking methods on the APDU object. In general, the applet performs the following steps:

Step 1. Retrieve the APDU buffer
The applet invokes the getBuffer() method to obtain a reference to the APDU buffer, which contains the message. When the applet receives the APDU object, only the first five APDU header bytes are available in the APDU buffer. They are the CLA, INS, P1, P2, and P3 bytes respectively. Byte P3 denotes the Lc byte, if the command has optional data. The applet can inspect the header bytes to determine the structure of the command and the instruction specified in the command.

Step 2. Receive data
If the command APDU contains optional data, the applet must direct the APDU object to receive incoming data by invoking the setIncomingAndReceive() method. The data is read into the APDU buffer following the five header bytes. The last byte in the header (Lc) shows the length of the incoming data. If the APDU buffer can't hold all the data, the applet can process the data piecemeal, or it can copy it to an internal buffer. In either case, it would then repeatedly call the receiveBytes() method to read additional data into the APDU buffer.

Step 3. Return data
After processing the command APDU, the applet can also return data to the CAD in the response APDU. The applet should first call the setOutgoing() method to set the data transfer direction to outbound, and to obtain the expected length of response (Le). Le is specified in the command APDU paired with this response APDU.

Next, the applet calls the setOutgoingLength() method to inform the CAD of the actual length of the response data. The applet can move the data to the APDU buffer and call the sendBytes() method to send out data. The sendBytes() method can be invoked repeatedly if the APDU buffer cannot hold the entire response data.

If the data is stored in an internal buffer, the applet invokes the sendByteLong() method to send data from the buffer.

If the response data is short enough to fit into the APDU buffer, the APDU class provides a convenient method for doing so: setOutgoingAndSend(). This method is a combination of setOutgoing,setOutgoingLength, and sendBytes. However, this method can only be invoked once, and no other send methods can be invoked afterwards.

Step 4. Return status word
Upon a successful return from the process() method, the JCRE automatically sends 0x9000 to indicate normal processing. At any point, if the applet detects any error, the applet can throw an ISOException by invoking the static method ISOException.throwIt(short reason). The status word is specified in the parameter reason. If the ISOException isn't handled by the applet, it will be caught by the JCRE. The JCRE retrieves the reason code and sends it as the status word.

Constructing the applet code
Once you've completed the applet-design phase, the second phase of writing applets is to construct the applet code. This section provides the wallet applet implementation.

The following documentation of the applet class is formatted in two columns. The left column contains Java code with Java-style comments. The right column provides further explanation of each segment of code.

package bank.purse; Java Card supports Java naming conventions for packages and identifiers.


import javacard.framework.*;
import javacardx.framework.*;

 
public class Wallet extends Applet { An applet is an instance of a class, which extends from: javacard.framework.Applet.


  /* constants declaration */
  // code of CLA byte in the command APDU header
  final static byte Wallet_CLA =(byte)0xB0;

CLA identifies the command structure.


  // codes of INS byte in the command APDU header
  final static byte VERIFY = (byte) 0x20;
  final static byte CREDIT = (byte) 0x30;
  final static byte DEBIT = (byte) 0x40;
  final static byte GET_BALANCE = (byte) 0x50;

INS specifies the application instructions.


  // maximum balance
  
  final static short MAX_BALANCE = 0x7FFF;
  
  // maximum transaction amount
  
  final static byte MAX_TRANSACTION_AMOUNT = 127;

Maximum balance and transaction amount.


  // maximum number of incorrect tries before the
  // PIN is blocked
  final static byte PIN_TRY_LIMIT =(byte)0x03;
  
  // maximum size PIN
  final static byte MAX_PIN_SIZE =(byte)0x08;

PIN object parameters.


  // signal that the PIN verification failed
  final static short SW_VERIFICATION_FAILED = 0x6300;
  
  // signal the PIN validation is required
  // for a credit or a debit transaction
  final static short SW_PIN_VERIFICATION_REQUIRED = 0x6301;
  
  // signal invalid transaction amount
  // amount > MAX_TRANSACTION_MAOUNT or amount < 0
  final static short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83;
  
  // signal that the balance exceed the maximum
  final static short SW_EXCEED_MAXIMUM_BALANCE = 0x6A84;
  
  // signal the balance becomes negative
  final static short SW_NEGATIVE_BALANCE = 0x6A85;

Applet-specific static words.


  /* instance variables declaration */
  OwnerPIN pin;
  short balance;

 


  private Wallet (byte[] bArray, short bOffset, byte bLength){
  
    // It is good programming practice to allocate
    // all the memory that an applet needs during
    // its lifetime inside the constructor
    pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
  
    // The installation parameters contain the PIN
    // initialization
    value pin.update(bArray, bOffset, bLength);
    register();
  } // end of the constructor
  
  

Private constructor -- an instance of class Wallet is

instantiated by its install method.The applet registers itself with the JCRE by calling the register method, which is defined in class Applet.


  public static void install(byte[] bArray, short bOffset, byte bLength) {
    // create a Wallet applet instance
    new Wallet(bArray, bOffset, bLength);
  } // end of install method

Method install is invoked by the JCRE to create an applet instance and to register the instance with the JCRE. The installation parameters are supplied in the byte array parameter, and must be in a format defined by the applet. They are used to initialize the applet instance.


  public boolean select() {
    // The applet declines to be selected
    // if the pin is blocked.
    if ( pin.getTriesRemaining() == 0 ) return false;
    return true;
  }// end of select method

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


  public void deselect() {
    // reset the pin value
    pin.reset();
  }

This method is called by the JCRE to inform the applet that it should perform any clean-up and bookkeeping tasks before the applet is deselected.


  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
    // At this point, only the first header bytes
    // [CLA, INS, P1, P2, P3] are available in
    // the APDU buffer.
    // The interface javacard.framework.ISO7816
    // declares constants to denote the offset of
    // these bytes in the APDU buffer
    byte[] buffer = apdu.getBuffer();

After the applet is successfully selected, the JCRE dispatches incoming APDUs to the process method.The APDU object is owned and maintained by the JCRE. It encapsulates details of the underlying transmission protocol (T0 or T1 as specified in ISO 7816-3) by providing a common interface.


    // check SELECT APDU command
    if ((buffer[ISO7816.OFFSET_CLA] == 0) &&
        (buffer[ISO7816.OFFSET_INS] == (byte)(0xA4))) return;

The JCRE also passes the SELECT APDU command to the applet.


    // verify the reset of commands have the
    // correct CLA byte, which specifies the
    // command structure
    if (buffer[ISO7816.OFFSET_CLA] != Wallet_CLA)
      ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

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


    switch (buffer[ISO7816.OFFSET_INS]) {
      case GET_BALANCE: getBalance(apdu);
        return;
      case DEBIT: debit(apdu);
        return;
      case CREDIT: credit(apdu);
        return;
      case VERIFY: verify(apdu);
        return;
      default: ISOException.throwIt (ISO7816.SW_INS_NOT_SUPPORTED);
    }
  } // end of process method

The main function of the process method is to perform the action specified in the APDU, and to return an appropriate response to the terminal. The INS byte specifies the type of action to be performed.


  private void credit(APDU apdu) {
    // access authentication
    if ( ! pin.isValidated()) ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
    byte[] buffer = apdu.getBuffer();
    // Lc byte denotes the number of bytes in the
    // data field of the command APDU
    byte numBytes = buffer[ISO7816.OFFSET_LC];
  
    // indicate that this APDU has incoming data
    // and receive data starting at the offset
    // ISO7816.OFFSET_CDATA following the 5 header
    // bytes.
    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(ISO7816.SW_WRONG_LENGTH);
  
    // get the credit amount
    byte creditAmount = buffer[ISO7816.OFFSET_CDATA];
  
    // check the credit amount
    if ( ( creditAmount > MAX_TRANSACTION_AMOUNT) || ( creditAmount < 0 ) )
      ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
  
    // check the new balance
    if ( ( balance + creditAmount) > MAX_BALANCE ) ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);
  
    // credit the amount
    balance = (short)(balance + creditAmount);
  
  } // end of deposit method

The parameter APDU object contains a data field, which specifies the amount to be added to the balance. Upon receiving the APDU object from the JCRE, the first 5 bytes (CLA, INS, P1, P2, Lc) are available in the APDU buffer. Their offsets in the APDU buffer are specified in the interface ISO7816. Because the data field is optional, the applet needs to explicitly inform the JCRE that it needs to retrieve additional data bytes. The card and the CAD communicate by exchanging APDU commands (the command APDU and response APDU). In the deposit case, the response APDU contains no data field. The JCRE returns the response APDU with status word 0x9000 (normal processing). Applet developers need not be concerned with the details of constructing the proper response APDU. When the JCRE catches an exception (which indicates an error during processing the command) the JCRE constructs the response APDU using the status word contained in the exception.


  private void debit(APDU apdu) {
  
    // access authentication
    if ( ! pin.isValidated()) ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);
  
    byte[] buffer = apdu.getBuffer();
    byte numBytes = (byte)(buffer[ISO7816.OFFSET_LC]);
    byte byteRead = (byte)(apdu.setIncomingAndReceive());
  
    if (byteRead != 1) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
  
    // get debit amount
    byte debitAmount = buffer[ISO7816.OFFSET_CDATA];
  
    // check debit amount
    if ( ( debitAmount > MAX_TRANSACTION_AMOUNT) || (debitAmount < 0 ) )
      ISOException.throwIt(SW_INVALID_TRANSACTION_AMOUNT);
  
    // check the new balance
    if ( ( balance-- debitAmount) < 0 ) ISOException.throwIt(SW_NEGATIVE_BALANCE);
  
    balance = (short) (balance -- debitAmount);
  } // end of debit method

In the debit method, the APDU object contains a data field that specifies the amount to be debited from the balance.


  private void getBalance(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    // 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
    short le = apdu.setOutgoing();
  
    if ( le < 2 ) ISOException.throwItISO7816.SW_WRONG_LENGTH);
  
    //informs the CAD the actual number of bytes
    //returned
    apdu.setOutgoingLength((byte)2);
  
    // move the balance data into the APDU buffer
    // starting at the offset 0
    buffer[0] = (byte)(balance >> 8);
    buffer[1] = (byte)(balance & 0xFF);
  
    // send the 2-balance byte at the offset
    // 0 in the apdu buffer
    apdu.sendBytes((short)0, (short)2);
  
  
  } // end of getBalance method

The method getBalance returns the Wallet's balance in the data field of the response APDU. Because the data field in the response APDU is optional, the applet must explicitly inform the JCRE of the additional data. The JCRE uses the data array in the APDU object buffer and the proper status word to construct a complete response APDU.


  private void verify(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    // retrieve the PIN data for validation.
    byte byteRead = (byte)(apdu.setIncomingAndReceive());
  
    // check pin
    // 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);
  } // end of validate method
} // end of class Wallet

The PIN is used in smart cards to protect data from unauthorized access. The number of unsuccessful tries in using the PIN can be recorded. The card will be blocked if the number of unsuccessful tries exceeds the maximum number of allowed tries. After the applet is successfully selected, the PIN must be validated before any other instruction can be performed on the applet.
Example wallet applet code

Implementing error checking
Error checking is an essential part of software development. In many cases, error checking counts for half of the development work.

Error checking is particularly important in smart card application development. An undetected error can cause the card to be blocked or result in the loss of critical data stored in the card.

Once an applet is installed in a smart card, it interfaces with the outside world only through APDU commands. Even though ISO 7816 sets the protocol standard, the applet and the terminal application must agree upon the significance of the value in each field of an APDU command.

In the above wallet applet code, much attention is devoted to detecting illegal or ill-formatted commands. In this example, the APDU commands are examined to ensure that the APDU header bytes (CLA, INS, P1, and P2) are set correctly, that the Lc or Le field matches with the data field length, that the PIN has been verified before a transaction, and that the balance and transaction amounts are valid.

In general, before performing the task indicated by an APDU command, an applet must validate the command according to the requirements of the applet. An applet should confirm the following before carrying out a command:

While executing the task, the applet should also detect whether the task can be performed successfully without leaving the applet in an invalid state.

As important as error checking is, it is just as important that the applet report errors that occur to the terminal. This ensures that the terminal application knows what is going on inside the card. When an error is detected, a Java Card applet will normally terminate the process and throw an ISOException containing a status word to indicate the processing state of the applet. If the ISOException is not handled by the applet, it will be caught by the JCRE, which then retrieves the status word and reports it to the terminal.

Conclusion
This article provides information you will need to write a Java Card applet. As when writing any software, the applet developer must first specify the function of the application and design its class structure. In addition to these steps, the applet developer must obtain the AIDs for the applet and the package that contains the applet, and specify the APDU commands the applet will support. The applet class must extend from the javacard.framework.Applet class. The class Applet defines a framework for applet interaction with the Java Card Runtime Environment during the applet lifecycle. A subclass of the Applet class must override methods in the Applet class to implement the applet's function.

With this article, you have the basic concepts of Java Card technology to get you started writing your own Java Card applets. For the specifications of the Java Card APIs, the Java Card Virtual Machine, and the Java Card Runtime Environment, you can visit the Java Card Web site listed below.


About the author
Zhiqun Chen is a Java Card engineer at Sun Microsystems. She has written financial Java Card applets. She is one of the engineers that design and implement Java Card APIs and she is currently implementing Sun's Java Card Virtual Machine reference implementation.


Advertisement: Support JavaWorld, click here!


HOME |  FEATURES |  COLUMNS |  NEWS & REVIEWS |  TIPS |  Q&A |  JW RESOURCES |  ABOUT JW |  FEEDBACK

Copyright © 2001 JavaWorld.com, an IDG Communications company