Chapter 12. Step-by-Step Applet Development Guide

In previous chapters, you have seen code fragments of an electronic wallet applet. This chapter walks you through the process of creating such an applet. The development steps are detailed, from designing the applet through constructing its code. At the end, the chapter provides a discussion of error checking for an applet.

Design 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 in four steps:

  1. Specify the functions of the applet.

  2. Request and assign AIDs to both the applet ansd the package containing the applet classes.

  3. Design the class structure of the applet programs.

  4. Define the interface between the applet and the host application.

Specify the Functions of the Applet

The example wallet applet stores electronic money and supports credit, debit, and check-balance functions. The Java smart card user can add money to the wallet (credit), make purchases or withdrawals (debit), and inquire about the current available balance.

To help prevent unauthorized use of the card, the applet applies a security algorithm. This algorithm requires the user to enter a PIN, a string of at most eight digits. The card user types his or her PIN on a keypad connected to the CAD. The security algorithm causes the card to block 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.

Note

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

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

Specify AIDs for the Applet

The Java classes of the wallet applet are defined in a single Java package. AIDs for the wallet applet and the applet package are defined in Table 12.1.

An AID consists of two parts: an RID (5 bytes long) and a PIX (0 to 11 bytes long). The RID (0xa0, 0x00, 0x00, 0x00, 0x62) in Table 12.1 is the RID for Sun Microsystems. Your organization must request an RID from the International Standards Organization (ISO). Your organization is responsible for managing the PIX assignment for packages and applets provided by your organization.

Table 12.1. AIDs for the wallet applet and the applet package

Field Value Length
RID 0xa0, 0x00, 0x00, 0x00, 0x62 5 bytes
Package PIX 0x03, 0x01, 0x0c, 0x06 4 bytes
Applet PIX 0x03, 0x01, 0x0c, 0x06, 0x01 5 bytes

Define the Class Structure and Method Functions of the Applet

As discussed in Chapter 7, a Java Card applet class must extend the javacard.framework.Applet class, whose public and protected methods are listed in Table 12.2. The applet overrides one or more of these public methods to implement the desired behavior. (For more information, refer to Chapters 7 and 9.) An applet must define and implement the static method install to create an applet instance and to register the instance with the JCRE by invoking one of the two register methods.

The process method in the base Applet class is an abstract class. Your applet must override it. In the process method, the applet interprets each APDU command and performs the function specified by the command. Typically, an applet supports a set of APDU commands. See the next section for a discussion of the APDU commands needed by the electronic wallet applet.

The select or the deselect method is invoked by the JCRE when the applet is selected or deselected. Your applet can override them to provide initialization or cleanup functions. However, not every applet requires initialization or cleanup.

Table 12.2. Public and protected methods defined in the class javacard.framework.Applet

public static void install (byte[] bArray, short bOffset, byte bLength)
public boolean select ()
public void deselect ()
public abstract void process (APDU apdu)
public Shareable getShareableInterfaceObject (AID client AID, byte parameter)
protected final void register()
protected final void register(byte[] bArray, short bOffset, byte bLength)
protected final boolean selectingApplet()

The applet uses the select or deselect method in the base class if it does not require additional functions during selection or deselection.

The getShareableInterfaceObject method is called to return a shareable interface object. The use of this method is covered in Chapter 9. For simplicity, the wallet applet in this chapter does not implement the object sharing function. Interested readers can add the function to the wallet applet by using the code examples in Chapter 9.

Two register methods and the selectingApplet method are protected final methods. They are invoked only by applets for registering an applet instance with the JCRE or detecting an applet SELECT APDU command.

Define the Interface between the Applet and Its Host Application

An applet running in a Java smart card communicates with the host application at the CAD side by using the application protocol data units (APDUs). In essence, the interface between an applet and its host application is a set of APDU commands that are agreed on and supported by both the applet and the host application.

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

  • The SELECT command instructs the JCRE to select the applet on the card.

  • The set of process commands defines the commands that the applet supports. They must be defined according to the intended behavior of the applet.

Java Card technology specifies the encoding of the SELECT APDU command used for selecting applets. As an applet developer, you are free to define the encoding of the process commands of an applet as long as they comply with the structure outlined in ISO 7816-4. That is, the SELECT command and each process command are pairs of command and response APDUs.

For each command APDU, the applet should first decode the value of each field in the header. If the optional data field is included, the applet should also determine the data format and the content. Knowing how to interpret the command and read the data, the applet can then execute the function requested by the command.

For the response APDU, the applet should define a set of status words to indicate the result of processing the corresponding 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 or a diagnosis of the error. If the optional data field is required in the response APDU, the applet should define what to return.

The wallet applet example supports credit, debit, and check-balance functions. In addition, it supports the VERIFY command for PIN verification. The SELECT command and four process APDU commands for the wallet applet are defined in Tables 12.312.12.

SELECT APDU

Table 12.3. SELECT APDU—command APDU

CLA INS P1 P2 Lc Data field Le
0x0 0xA4 0x04 0x0 0x0A 0xa0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0c, 0x06, 0x01 N/A

The command header (CLA, INS, P1, and P2) must be coded as in Table 12.3 so that the JCRE can identify it as a SELECT APDU. 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, and the SELECT APDU is forwarded to the applet's process method for further processing.

Table 12.4. SELECT APDU—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

Table 12.5. VERIFY APDU—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.

Table 12.6. VERIFY APDU—response APDU

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

CREDIT APDU

Table 12.7. CREDIT APDU—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

Table 12.8. CREDIT APDU—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

Table 12.9. DEBIT APDU—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

Table 12.10. DEBIT APDU—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

Table 12.11. GET BALANCE APDU—command APDU

CLA INS P1 P2 Lc Data field Le
0xB0 0x50 0x0 0x0 N/A N/A 2

The data field of the response APDU contains the balance amount.

Table 12.12. GET BALANCE APDU—response APDU

Data Status word Meaning of status word
Balance amount 0x9000 Successful processing

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

Construct the Applet Code

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

Wallet Applet Code

package com.sun.javacard.samples.wallet;
import javacard.framework.*;

public class WalletApp extends Applet {

   // codes of CLA byte in the command APDUs
   final static byte Wallet_CLA = (byte)0xB0;

   // codes of INS byte in the command APDUs
   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;

   // maximum wallet balance
   final static short MAX_BALANCE = 10000;
   // maximum transaction amount
   final static byte MAX_TRANSACTION_AMOUNT = 100;

   // 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;

   // Applet-specific status words:
   final static short SW_VERIFICATION_FAILED = 0x6300;
   final static short SW_PIN_VERIFICATION_REQUIRED = 0x6301;
   final static short SW_INVALID_TRANSACTION_AMOUNT = 0x6A83;
   final static short SW_EXCEED_MAXIMUM_BALANCE = 0x6A84;
   final static short SW_NEGATIVE_BALANCE = 0x6A85;

   // instance variables declaration
   OwnerPIN pin;
   short balance;

   /**
    * called by the JCRE to create an applet instance
    */
   public static void install(byte[] bArray,
                              short bOffset,
                              byte bLength) {

      // create a Wallet applet instance
      new WalletApp(bArray, bOffset, bLength);

   } // end of install method

   /**
    * private constructor — called by the install method to
    * instantiate a WalletApp instance
    */
   private WalletApp (byte[] bArray, short bOffset, byte bLength){

      pin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);

      // bArray contains the PIN initialization value
      pin.update(bArray, bOffset, bLength);

      // register the applet instance with the JCRE
      register();

   } // end of the constructor

   /**
    * initialize the applet when it is selected
    */
   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
   /**
    * perform any cleanup and bookkeeping tasks before
    * the applet is deselected
    */
   public void deselect() {

      // reset the pin
      pin.reset();
   }

   /**
    * process APDUs
    */
   public void process(APDU apdu) {

      // APDU object carries a byte array (buffer) to
      // transfer incoming and outgoing APDU header
      // and data bytes between the card and the host

      // at this point, only the first five bytes
      // [CLA, INS, P1, P2, P3] are available in
      // the APDU buffer
      byte[] buffer = apdu.getBuffer();

      // return if the APDU is the applet SELECT command
      if (selectingApplet())
         return;

      // verify the CLA byte
      if (buffer[ISO7816.OFFSET_CLA] != Wallet_CLA)
         ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);

      // check the INS byte to decide which service method to call
      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

   /**
    * add money to the wallet
    */
   private void credit(APDU apdu) {

      // verify authentication
      if (!pin.isValidated())
         ISOException.throwIt(SW_PIN_VERIFICATION_REQUIRED);

      byte[] buffer = apdu.getBuffer();

      // get the number of bytes in the
      // data field of the command APDU
      byte numBytes = buffer[ISO7816.OFFSET_LC];

      // recieve data
      // data are read into the apdu buffer
      // at the offset ISO7816.OFFSET_CDATA
      byte byteRead = (byte)(apdu.setIncomingAndReceive());

      // error if the number of data bytes
      // read does not match the number in the Lc byte
      if (( numBytes != 1 ) || (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 ((short)( balance + creditAmount)  > MAX_BALANCE)
         ISOException.throwIt(SW_EXCEED_MAXIMUM_BALANCE);

      // credit the amount
      balance = (short)(balance + creditAmount);
      return;

   } // end of deposit method

   /**
    * withdraw money from the wallet
    */
   private void debit(APDU apdu) {

      // verify 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 (( numBytes != 1 ) || (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 ((short)( balance - debitAmount ) < (short)0)
         ISOException.throwIt(SW_NEGATIVE_BALANCE);

      balance = (short) (balance - debitAmount);

   } // end of debit method

   /**
    * the method returns the wallet's balance
    */
   private void getBalance(APDU apdu) {

      byte[] buffer = apdu.getBuffer();

      // inform the JCRE that the applet has data to return
      short le = apdu.setOutgoing();

      // set the actual number of the outgoing data bytes
      apdu.setOutgoingLength((byte)2);

      // write the balance into the APDU buffer at the offset 0
      Util.setShort(buffer, (short)0, balance);

      // send the 2-byte balance at the offset
      // 0 in the apdu buffer
      apdu.sendBytes((short)0, (short)2);

   } // end of getBalance method

   /**
    * verify the PIN
    */
   private void verify(APDU apdu) {

      byte[] buffer = apdu.getBuffer();

      // receive the PIN data for validation.
      byte byteRead = (byte)(apdu.setIncomingAndReceive());

      // check pin
      // the PIN data is read into the APDU buffer
      // starting 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 verify method

} // end of class Wallet

Implement Error Checking

The next step in coding a Java Card applet is to provide for error checking. Error checking is essential in any software development and typically requires a significant amount of the total 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 host application must agree on the significance of the value in each field of an APDU command.

In the 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 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 attempting to carry out a command:

  • The APDU command is supported by the applet.

  • The APDU command is well formatted.

  • The APDU command meets the security or other internal conditions of the applet.

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 to the host errors that occur. This ensures that the host application knows what is going on inside the applet. 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 host.

What's the Next Step?

The next step during the applet development process is to test the wallet applet in a Java Card simulation or emulation environment. You can find instructions on how to complete applet testing at the Web site http://java.sun.com/docs/books/series/javacard. You can also download the Java Card development tools, the Java Card API classes, and related documents from the Java Card Web site http://java.sun.com/docs/books/javacard.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.70.203