An Introduction to Java Card Technology - Part 2, The Java Card Applet

By C. Enrique Ortiz, September 2003    

Part 1 of this article covered the high-level aspects of Java Card technology - what smart cards are, the elements of a Java Card application, the communication aspects, and a summary of the different Java Card technology specifications. In this part we focus on the development aspects of Java Card applets: the typical steps when developing a Java Card application, the Sun Java Card Development kit, and the Java Card and Java Card RMI APIs.

Developing a Java Card Application

The typical steps when creating a Java Card application are:

  1. Write the Java source.
  2. Compile your source.
  3. Convert the class files into a Converted Applet (CAP) file.
  4. Verify that the CAP is valid; this step is optional.
  5. Install the CAP file.

The first two steps are the same as when developing traditional programs in the Java programming language: write .java files and compile them into .class files. Once you have created Java Card class files, though, the process changes.

The Java Card Virtual Machine (JCVM) is split into an off-card JVM and an on-card JVM. This split moves expensive operations off-card and allows for a small memory footprint on the card itself, but it results in extra steps when developing Java Card applications.

Before the Java Card classes can be loaded into a Java Card device, they must be converted to the standard CAP file format, and then optionally verified:

  • Conversion entails transforming each Java package into a CAP file, which contains the combined binary representation of classes and interfaces in a package. Conversion is an off-card operation.
  • Verification is an optional process to validate the CAP file for structure, valid bytecode subset, and inter-package dependencies. You may want to do verification on third-party vendor packages that you use, or if your converter tool comes from a third-party vendor. Verification is typically an off-card operation, but some card products may include an on-board verifier.

Once verified, the CAP file is ready to be installed on the Java Card device.

The Sun Java Card Development Kit

You can write Java Card applets, and even test them without a smart card or card reader, using the Sun Java Card Development Kit. This kit includes all the basic tools you need to develop and test Java Card applets:

  • The Java Card Workstation Development Environment (JCWDE), a convenient, easy to use Java Card simulation tool that allows developers to execute class files directly, without having to convert and install CAP files. The JCWDE can be integrated with a debugger and IDEs.

    Starting with version 2.2.1 of the development kit, JCWDE supports Java Card RMI (JCRMI). Note that the JCWDE is not a full-blown Java Card simulator. It does not support a number of JCRE features, such as package installation, applet instance creation, firewalls, and transactions. Please refer to the development kit's User's Guide for more information.
  • The C-language Java Card Runtime Environment (C-JCRE), an executable reference implementation written in C. The C-JCRE is a fully compliant implementation of the Java Card APIs, VM, and Runtime Environment. It enables a developer to test the behavior of its applets in a workstation environment accurately.

    The C-JCRE has a few limitations: it supports up to eight remote references that can be returned during a card session, up to 16 remote objects that can be simultaneously exported, up to eight parameters of array type in remote methods, up to 32 supported Java packages, and up to 16 Java Card applets. For more information on these limitations, refer to the Java Card Development Kit User's Guide.
  • The Java Card converter tool, for generating CAP files.
  • The Java Card verifier, for optionally checking the validity of CAP and export files.
  • An apdutool for sending and receiving Application Protocol Data Units (APDUs). This is how you send APDUs to your Java Card applet during testing. You can create script files that the apdutool reads, to send APDUs to the C-JCRE or JCWDE.
  • A capdump tool for dumping the contents of CAP, and exp2text to print EXP files.
  • A scriptgen tool, to convert CAP files into APDU script files. This tool is also referred to as the off-card installer.
  • Supporting libraries (class files and export files for the Java Card API), documentation, and samples.
While the Sun Java Card Development kit allows you to write and test Java Card applets, deploying a real end-to-end smart-card application requires tools not included in the development kit, for example the use of terminal-side APIs such as the OpenCard and Global Platform APIs. It may also require the use of tools such as Subscriber Identification Module (SIM) toolkits to help you manage the SIMs.

Table 1 shows the directory structure of the toolkit (the Windows version), as well as the contents of the bin directory that contains the development tools.

Figure 1a. Development Kit Directory Structure Figure 1b. Contents of bin directory
Figure 1a. Development Kit Directory Structure Figure 1b. Contents of bin directory

Now let's revisit the Java Card development steps, this time with the Sun Java Card Development kit in mind:

  1. Write the Java source using your favorite editor or IDE.
  2. Compile your source using your favorite compiler or IDE.
  3. Optionally, test your Java Card applet using the JCWDE simulator. Recall that the JCWDE is not a full-blown simulator.
  4. Convert the class files into a Converted Applet (CAP) file using the converter tool in the toolkit's bin directory. Note that, in addition to class files, another input to the converter tool are export files, which provide information about packages that are imported (referenced) by your application; these are packages also loaded in the card. Export files are also an output of the converter tool.
  5. Optionally, verify the CAP for validity. This step includes using the verifycap script to verify the validity of the CAP file, using verifyexp to verify the export files, and using verifyrev to verify the binary compatibility between package revisions. Tools verifycap, verifyexp, and verifyrev scripts are all found in the bin directory.
  6. Install the CAP file. Use the scriptgen tool to convert the CAP file into an (installation) APDU script file. Then use the apdutool to send the script file (installation APDU commands and CAP file) to the C-JCRE, or a JCRE on the Java Card device. The JCRE stores the CAP file in the card's memory.

The following figure summarizes these steps. Note that each Java Card vendor provides its own tools, but the steps for developing a Java Card applet generally are the same across development kits:

Figure 2. Java Card Development Steps
Figure 2. Java Card Development Steps
(click for larger image)

For more information on how to use Sun's Java Card Development Kit, refer to the Java Card Development Kit User's Guide, found in the kit's doc directory. Another excellent reference is the article " Using the Java Card Development Kit."

Writing a Card-Side Java Card Applet

You can write Java Card applets ( javacard.framework.Applet) using either of two models: the traditional Java Card API, or the Java Card Remote Method Invocation (JCRMI) API.

Using the Java Card API

Developing a Java Card applet is a two-step process:

  1. Defining the command and response APDUs that serve as the interface between the host application and the applet
  2. Writing the Java Card applet itself

First, let's look at the structure of a Java Card applet.

Applet Structure

Listing 1 shows how a typical Java Card applet is constructed:

import javacard.framework.*
...
public class MyApplet extends Applet {
    // Definitions of APDU-related instruction codes
    ...
    MyApplet() {...} // Constructor
    // Life-cycle methods
    install() {...}
    select() {...}
    deselect() {...}
    process() {...}
    // Private methods
    ...
}

Listing 1. Structure of a Java Card Applet

A Java Card applet customarily defines its APDU-related instructions, its constructor, then the Java Card applet life-cycle methods: install(), select(), deselect(), and process(). Finally, it defines any appropriate private methods.

Defining APDU Instructions
Different Java Card applications have different interface (APDU) requirements. A credit-card applet may support ways to validate a PIN number, make credit and debit transactions, and check the account's balance. A health insurance applet may provide access to health insurance information, coverage limits, doctors, patient information, and so on. The exact APDUs that you define depend on your application's requirements.

As an example, let's work through parts of the classical Wallet credit-card example. You can find the complete source code for this and other examples under samples directory in the Sun Java Card Development kit.

We'll start by defining an APDU command that queries for the current-balance figure stored in the Java Card device. Note that in a real credit card application we would also define credit and debit commands. We'll assign our Get Balance APDU an instruction class of 0x80 and an instruction of 0x30. The Get Balance APDU doesn't need any instruction parameters or a data field, and the expected response consists of two bytes that contain the balance. The next table describes the Get Balance APDU command:

Table 1 - The Get Balance APDU Command

Name CLA INS P1 P2 Lc Data Field Le (size of response)
Get Balance 0x80 0x30 0 0 N/A N/A 2


While the Get Balance command doesn't define incoming data, some command APDUs will. As an example, let's define a Verify PIN APDU command that validates a PIN number that is passed from the card-reader. The next table defines the Verify APDU:

Table 2 - The Verify APDU Command

Name CLA INS P1 P2 Lc Data Field Le (size of response)
Verify PIN 0x80 0x20 0 0 PIN Len PIN Value N/A


Note that the Le field, the size of the response is N/A. This is because there is no application-specific response to Verify PIN; success or failure is indicated via the status words in the response APDU.

To facilitate APDU processing, the javacard.framework.ISO7816 interface defines a number of constants we can use to retrieve the various APDU fields from the input buffer that is passed to the applet via the process() method:

...
byte cla = buf[ISO7816.OFFSET_CLA];
byte ins = buf[ISO7816.OFFSET_INS];
byte p1 = buf[ISO7816.OFFSET_P1];
byte p2 = buf[ISO7816.OFFSET_P2];
byte lc = buf[ISO7816.OFFSET_LC];
...
// Get APDU data, by copying lc bytes from OFFSET_CDATA, into 
// reusable buffer databuf.
Util.arrayCopy(buf, ISO7816.OFFSET_CDATA, databuf, 0, lc);
...

Listing 2. Using the ISO-7816-4 Constants

Now we'll define the class (CLA) and the instructions (INS) for the Get Balance and Verify commands, the size of the get balance response, and the error return code if the PIN verification fails.

...
// MyApplet APDU definitions
final static byte MyAPPLET_CLA = (byte)0x80;
final static byte VERIFY_INS = (byte)0x20;
final static byte GET_BALANCE_INS = (byte) 0x30;
final static short GET_BALANCE_RESPONSE_SZ = 2;
//  Exception (return code) if PIN verify fails.
final static short SW_PINVERIFY_FAILED = (short)0x6900;
...

Listing 3. Applet's APDU Definitions

Next, let's define the applet constructor, and the lifecycle methods.

The Constructor
Define a private constructor that initializes the object's state. This constructor is called from the install() method; in other words, the constructor is called only once during the lifetime of the applet:

/**
 * Private Constructor.
 */
private MyApplet() {
          super();

    // ... Allocate all objects needed during the applet's 
    // lifetime.
    ownerPin = new OwnerPIN(PIN_TRY_LIMIT, MAX_PIN_SIZE);
    ...
    //  Register this applet instance with the JCRE.
    register();
}

Listing 4. The Applet Constructor

In this example we use a javacard.framework.OwnerPIN, an object that represents a personal identification number; this object will exist for the lifetime of the Java Card Applet. Recall from "Managing Memory and Objects" in Part 1 that in a Java Card environment, arrays and primitive types should be declared at object declaration, and that you should minimize object instantiation in favor of object reuse. Create objects only once during the applet lifetime. An easy way to do so is to create the objects in the constructor, and invoke this constructor from the install() method - which itself is invoked only once during the applet lifetime. To promote reuse, objects should remain in scope or adequately referenced for the life of the applet, and the values of their member variables reset appropriately before reuse. Because a garbage collector is not always available, an application may never reclaim the storage allocated to objects that go out of extent.

The install() Method
The JCRE invokes install() during the installation process. You must override this method inherited from the javacard.framework.Applet class, and your install() method must instantiate the applet, as here:

/**
 * Installs the Applet. Creates an instance of MyApplet. The 
 * JCRE calls this static method during applet installation.
 * @param bArray install parameter array.
 * @param bOffset where install data begins.
 * @param bLength install parameter data length.
 * @throw ISOException if the install method fails.
 */
public static void install(byte[] bArray, short bOffset, byte bLength) 
throws ISOException {
    // Instantiate MyApplet
    new MyApplet();
    ...
}

Listing 5. The install() Applet Life-Cycle Method

The install() method must directly or indirectly call the register() method to complete the installation; failing to do so will cause installation to fail. In our sample, the constructor calls register().

The select() Method
The JCRE invokes select() to notify the applet that it has been selected for APDU processing. You don't have to implement this method unless you want to provide session initialization or personalization. The select() method must return true to indicate that it is ready to process incoming APDUs, or false to decline selection. The default implementation by javacard.framework.Applet class returns true.

/**
 * Called by the JCRE to inform this applet that it has been 
 * selected. Perform any initialization that may be required to 
 * process APDU commands. This method returns a boolean to   
 * indicate whether it is ready to accept incoming APDU commands 
 * via its process() method.
 * @return If this method returns false, it indicates to the JCRE  
 * that this Applet declines to be selected.
 */
public boolean select() {
    //  Perform any applet-specific session initialization.
    return true;
}

Listing 6. The select() Applet Life-Cycle Method

The deselect() Method
The JCRE invokes deselect() to notify the applet that it has been deselected. You don't have to implement this method unless you want to provide session cleanup. The default implementation by the javacard.framework.Applet class does nothing.

/**
 * Called by the JCRE to inform this currently selected applet 
 * it is being deselected on this logical channel. Performs 
 * the session cleanup.
 */
public void deselect() {
    // Perform appropriate cleanup.
    ownerPin.reset();
}

Listing 7. The deselect() Applet Life-Cycle Method

In our example, we reset the PIN.

The process() Method - Working with APDUs
Once an applet has been selected it is ready to receive command APDUs, as described in the "Life-Cycle of a Java Card Applet" section of Part 1.

Recall that APDU commands are sent to the card from a host-side (client) application, as illustrated next:

Figure 3. APDU Commands and Responses Flow Between a Host Application and a Java Card Applet
Figure 3. APDU Commands and Responses Flow Between a Host Application and a Java Card Applet
(click for larger image)

Each time the JCRE receives an APDU command (from the host application via the card-reader, or the apdutool if using the Sun Java Card Development kit) it calls the applet's process() method, passing it the incoming command as an argument (this argument in the APDU command input buffer). The process() method then:

  1. Extracts the APDU CLA and INS fields
  2. Retrieves the application-specific P1, P2, and data fields
  3. Processes the APDU data
  4. Generates and sends a response
  5. Returns gracefully, or throws the appropriate ISO exception

At that point, the JCRE sends the appropriate status words back to the host application, via the card reader.

Listing 8 shows a sample process() method.

/**
 * Called by the JCRE to process an incoming APDU command. An 
 * applet is expected to perform the action requested and return 
 * response data if any to the terminal.
 *
 * Upon normal return from this method the JCRE sends the ISO- 
 * 7816-4-defined success status (90 00) in the APDU response. If 
 * this method throws an ISOException the JCRE sends the 
 * associated reason code as the response status instead.
 * @param apdu is the incoming APDU.
 * @throw ISOException if the process method fails.
 */
public void process(APDU apdu) throws ISOException {

     
                    
// Get the incoming APDU buffer.
byte[] buffer = apdu.getBuffer();
// Get the CLA; mask out the logical-channel info.
buffer[ISO7816.OFFSET_CLA] = (byte)(buffer[ISO7816.OFFSET_CLA] & (byte)0xFC);
// If INS is Select, return - no need to process select

// here.
if ((buffer[ISO7816.OFFSET_CLA] == 0) && (buffer[ISO7816.OFFSET_INS] == (byte)(0xA4)) ) return;
// If unrecognized class, return "unsupported class."
if (buffer[ISO7816.OFFSET_CLA] != MyAPPLET_CLA) ISOException.throwIt(ISO7816.SW_CLA_NOT_SUPPORTED);
// Process (application-specific) APDU commands aimed at

// MyApplet.
switch (buffer[ISO7816.OFFSET_INS]) { case VERIFY_INS: verify(apdu); break; case GET_BALANCE_INS: getBalance(apdu); break; default: ISOException.throwIt(ISO7816.SW_INS_NOT_SUPPORTED); break; } }

Listing 8. The process() Applet Life-cycle Method

Our process() method invokes the getBalance() and verify() methods. Listing 9 shows the getBalance() method, which processes the get balance APDU and returns the balance stored in the card.

/**
 * Retrieves and returns the balance stored in this card.
 * @param apdu is the incoming APDU.
 */
private void getBalance(APDU apdu) {

     
                    
// Get the incoming APDU buffer.
byte[] buffer = apdu.getBuffer();
// Set the data transfer direction to outbound and obtain

// the expected length of response (Le).
short le = apdu.setOutgoing();
// If the expected size is incorrect, send a wrong-length

// status word.
if (le != GET_BALANCE_RESPONSE_SZ) ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);
// Set the actual number of bytes in the response data field.

apdu.setOutgoingLength
((byte)GET_BALANCE_RESPONSE_SZ);
// Set the response data field; split the balance into 2

// separate bytes.
buffer[0] = (byte)(balance >> 8); buffer[1] = (byte)(balance & 0xFF);
// Send the 2-byte balance starting at the offset in the APDU

// buffer.

apdu.sendBytes
((short)0, (short)GET_BALANCE_RESPONSE_SZ); }

Listing 9. Processing the Get Balance APDU

The getBalance() method gets a reference to the APDU buffer by calling the APDU.getBuffer() method. Before returning the response (the current balance), the applet must set the JCRE mode to send by invoking the APDU.setOutgoing() method, which conveniently returns the size of the expected response. We must also set the actual number of bytes in the response data field, by calling APDU.setOutgoingLenth(). The response in the APDU buffer is actually sent by calling APDU.sendBytes().

Applets don't directly send return codes (status words); the JCRE takes care of that, once the applet invokes APDU.setOutgoing() and supplies any requested information. The values of the status words vary depending on how the process() method returns to the JCRE. If all has gone well, the JCRE will return 9000, which indicates no error. Your applet can return an error code by throwing one of the exceptions defined in the ISO7816 interface, or an application-specific value. In Listing 9, method getBalance() throws an ISO7816.SW_WRONG_LENGTH code if the size of the expected response is incorrect. For the valid status code values refer to the definition of the ISO7816 interface, or to the section "The Response APDU" in this article's first installment.

Now let's look at the verify() method, in Listing 10. Because we defined the verify PIN APDU command to contain data, the verify() method must call the APDU.setIncomingAndReceive() method, which sets the JCRE to receive mode, then receives the incoming data.

/**
 * Validates (verifies) the Owner's PIN number.
 * @param apdu is the incoming APDU.
 */
private void verify(APDU apdu) {

     
                    
// Get the incoming APDU buffer.
byte[] buffer = apdu.getBuffer();
// Get the PIN data.
byte bytesRead = (byte)apdu.setIncomingAndReceive();
// Check/verify the PIN number. Read bytesRead number of PIN

// bytes into the APDU buffer at the offset

// ISO7816.OFFSET_CDATA.
if (ownerPin.check(buffer,
ISO7816.OFFSET_CDATA
, byteRead) == false ) ISOException.throwIt(
SW_PINVERIFY_FAILED
); }

Listing 10. Processing the Verify APDU

The method gets a reference to the APDU buffer by calling APDU.getBuffer(), calls APDU.setIncomingAndReceive() to receive the command data, gets the PIN data from the incoming APDU buffer, and verifies the PIN. A verification failure causes the status code 6900 to be sent back to the host application.

Sometimes there's more incoming data than can fit in the APDU buffer, and the applet must read the data in chunks until there is no more data to be read. In such cases, we must first invoke APDU.setIncomingAndReceive(), then call APDU.receiveBytes() repeatedly until no more data is available. Listing 11 shows how to read large amounts of incoming data.

...
byte[] buffer = apdu.getBuffer();
short bytes_left = (short) buffer[ISO.OFFSET_LC];
short readCount = apdu.setIncomingAndReceive();
while (bytes_left > 0) {

     
                    
// Process received data in buffer; copy chunk to temp buf.

Util.arrayCopy
(buffer, ISO.OFFSET_CDATA, tbuf, 0, readCount); bytes_left -= readCount;
// Get more data
readCount =
apdu.receiveBytes
(ISO.OFFSET_CDDATA); } ...

Listing 11. Reading Large Amounts of Incoming Data

As each chunk is read, the applet could append it to another buffer, or just process it.

Using the Java Card RMI API

The second model you can follow for programming Java Card applets is the Java Card RMI (JCRMI), which is based on the J2SE RMI distributed-object model.

This approach provides an object-centric model, in which the APDU communication and handling you saw on the preceding section are abstracted; instead, you deal with objects. This simplifies the programming and integration of Java Card technology-based devices.

In the RMI model a server application creates and makes accessible remote objects, and a client application obtains remote references to the server's remote objects, and then invokes remote methods on them. In JCRMI, the Java Card applet is the server, and the host application is the client.

Brief Introduction to Java Card RMI
Two packages provide the support for Java Card RMI:

  • java.rmi defines a subset of the Java 2 Standard Edition java.rmi package. It defines the Remote interface and the RemoteException class. None of the traditional java.rmi classes are included.
  •  
  • javacard.framework.service defines Java Card applet services classes, including RMI services classes CardRemoteObject and the RMIService.

    Class CardRemoteObject defines two methods to enable and disable the remote access of an object from outside the card. Class RMIService processes RMI requests (translates incoming command APDUs to remote method invocations).

Writing a JCRMI application is similar to writing a typical RMI-based application:

  1. Define as an interface the behavior of the remote class.
  2. Write the server implementation of the remote class, and supporting classes.
  3. Write a client program that uses the remote service, and supporting classes.

Note that JCRMI does not change the fundamental structure or life-cycle of applets, as you'll see shortly.

The Remote Interface
The first step in creating a remote service is to define its visible behavior. The remote interfaces define the services your applet provides. As in standard J2SE RMI, all Java Card RMI remote interfaces must extend the java.rmi.Remote interface. To illustrate, here is a remote interface that exposes a method to get the balance stored in the card:

import java.rmi.*;
import javacard.framework.*;

public interface MyRemoteInterface extends Remote {
    ...  
    public short getBalance() throws RemoteException;
    ...
    // A complete credit card application would also define other  
    // methods such as credit() and debit() methods.
    ...
}

Listing 12. The Remote Interface

MyRemoteInterface defines the remote methods, in our example a getBalance() method, to retrieve the balance that is stored in the smart card. Note that except for the Java Card-specific imports, this remote interface looks exactly like a standard RMI remote interface.

The Server Implementation
The next step is implementing the server's behavior. The server implementation comprises the Java Card applet, the implementation of any remote interfaces you've defined, and any related classes specific to your application.

The Java Card Applet
The Java Card applet is the JCRMI server, and the owner of remote objects that are available to host (client) applications. The structure of a typical Java Card RMI applet is illustrated in the next figure:

Figure 4. Structure of a Typical Java Card RMI Applet
Figure 4. Structure of a Typical Java Card RMI Applet

When compared to an applet that processes APDU messages explicitly, the JCRMI-based applet is more of an object container. As you can see in Figure 4, the JCRMI-based applet has one or more remote objects, an APDU Dispatcher, and an RMIService that receives APDUs and translates them into remote method calls. Java Card remote classes can extend the CardRemoteObject class, to export the object automatically, making it visible for remote use.

JCRMI applets must extend javacard.framework.Applet, follow the standard applet structure, and define appropriate life-cycle methods. It must install and register itself, and dispatch APDUs. The next code snippet illustrates the typical structure of a JCRMI-based applet:

public class MyApplet extends javacard.framework.Applet {
    
    private Dispatcher disp;
    private RemoteService serv;
    private Remote myRemoteInterface;
    
    /**
     * Construct the applet. Here instantiate the remote 
     * implementation(s), the APDU Dispatcher, and the   
     * RMIService.  Before returning, register the applet.
     */
    public MyApplet () {
        // Create the implementation for my applet.
         
                    
myRemoteInterface = new MyRemoteInterfaceImpl();
// Create a new Dispatcher that can hold a maximum of 1 // service, the RMIService. disp =
new Dispatcher
((short)1); // Create the RMIService serv =
new RMIService(myRemoteInterface);

disp.addService(serv, Dispatcher.PROCESS_COMMAND);
// Complete the registration process
register();
} ...

The applet creates a Dispatcher, and an RMIService to process incoming JCRMI APDUs.
    ...
   /**
    * Installs the Applet. Creates an instance of MyApplet. 
    * The JCRE calls this static method during applet 
    * installation.
    * @param bArray install parameter array.
    * @param bOffset where install data begins.
    * @param bLength install parameter data length.
    */
    public static void  
                    
install
(byte[] aid, short s, byte b) { new MyApplet(); }

In the Java Card environment, the lifetime of the JVM is the lifetime of the physical card, and not all Java Card implementations provide a garbage collector, so you need to minimize memory allocations. Create objects at installation time so memory is allocated to them only once.
   /**
    * Called by the JCRE to process an incoming APDU command. An 
    * applet is expected to perform the action requested and 
    * return response data, if any.
    *
    * This JCRMI version of the applet dispatches remote  
    * invocation APDUs by invoking the Dispatcher.
    *
    * Upon normal return from this method the JCRE sends the ISO- 
    * 7816-4-defined success status (90 00) in the APDU response. 
    * If this method throws an ISOException, the JCRE sends the 
    * associated reason code as the response status instead.
    * @param apdu is the incoming APDU.
    * @throw ISOException if the install method fails.
    */
    public void  
                    
process
(APDU apdu) throws ISOException { // Dispatch the incoming command APDU to the RMIService.
disp.process
(apdu); }

The applet's process() method receives an APDU command and dispatches it to the RMIService, which processes the command by translating it into an RMI call and subsequent response.
}

Listing 13. The Java Card RMI Applet

Implementing the Remote Object
Implementing a JCRMI remote object is similar to implementing standard J2SE RMI remote objects. The main difference is that in JCRMI your remote object has the option of extending CardRemoteObject (in addition to implementing your remote interface).

CardRemoteObject, which defines two methods, export() and unexport(), to enable and disable respectively access to an object from outside the card. By extending CardRemoteObject, you automatically export all the methods of your remote object. If you decide not to extend CardRemoteObject, you will be responsible for exporting them by calling CardRemoteObject.export().

import java.rmi.RemoteException;
import javacard.framework.service.CardRemoteObject;
import javacard.framework.Util;
import javacard.framework.UserException;
/**
 * Provides the implementation for MyRemoteInterface.
 */
public class MyRemoteImpl  
                    
extends CardRemoteObject implements MyRemoteInterface
{ /** The balance. */ private short balance = 0; /** * The Constructor invokes the superclass constructor, * which exports this remote implementation. */
public MyRemoteImpl() {

super(); // make this remote object visible
} /** * This method returns the balance. * @return the stored balance. * @throws RemoteException if a JCRMI exception is * encountered */ public short getBalance() throws RemoteException { return balance; } // Other methods ... }

Listing 14. The Remote Object Implementation

Flow of a Completed Java Card RMI Application
Let's summarize the flow of a JCRMI application. The client (host) application makes RMI calls by passing RMI APDUs to the on-card JCRE, which in turn forwards these APDUs to the appropriate JCRMI applet. This applet dispatches the received APDU to the RMIService, which in turn processes the APDU and translates it into an RMI call. The typical flow of a JCRMI applet is illustrated here:

Figure 5. Flow of a Java Card RMI-Based Applet
Figure 5. Flow of a Java Card RMI-Based Applet

In a nutshell, JCRMI provides a distributed object model mechanism on top of the APDU-based messaging model. JCRMI messages are encapsulated within APDU messages passed to the RMIService, which is responsible of decoding APDU commands, and translating these into method invocations and responses. This allows the server and the client to communicate, passing method information, arguments, and return values back and forth.

Summary

This second part of An Introduction to Java Card Technology covered the development aspects of Java Card applets: the structure of a Java Card applet, the Sun Java Card Development kit, and the APIs and programming models that are available to you to write applets: the Java Card API, and the Java Card RMI API.

The next and last installment, Part 3, will cover host applications, and some of the Java APIs that are available for writing them: the OpenCard Framework, the Java Card RMI Client API, and the Security and Trust Services API (SATSA) for J2ME.

Smart cards with Java Card technology are the most portable and secure way of carrying digital personal information and computational capabilities - a very powerful and needed technology in today's digital world.

Links of Interest

  • The following references can be found in the Java Card Development Kit (JCDK):
    • Java Card 2.2 Application Programming Interface
    • Java Card 2.2 Runtime Environment (JCRE) Specification
    • Java Card 2.2 Development Kit User's Guide
    • Java Card 2.2 Virtual Machine Specification
    • Java Card Applet Developer's Guide
  • Java Card Programming Notes
  • Java Card Technology for Smart Cards: Architecture and Programmer's Guide by Zhiqun Chen
  • Developing a Java Card Applet

Acknowledgements

Many thanks to members of the Java Card team: Florian Tournier, Eduard de Jong, Oscar A. Montemayor, and Victor Olkhovets, and to Richard Marejka and Brian Christeson for their great contributions and feedback to this article.

Rate and Review
Tell us what you think of the content of this page.
Excellent   Good   Fair   Poor  
Comments:
Your email address (no reply is possible without an address):
Sun Privacy Policy

Note: We are not able to respond to all submitted comments.