Writing a Java Card Applet

This article introduces smart cards, gives a brief overview of Java Card technology, and by stepping you through the code of a sample applet distributed with a Java Card toolkit, shows you how to code a Java Card applet. This is the first in a series of articles on Java Card applets. After you write a Java Card applet, you're ready to test and deploy it. Future articles will describe how to perform those tasks.

It's hard to imagine making major purchases--and many types of minor ones--without credit cards. They've become almost ubiquitous in modern economies. But as familiar as these plastic cards have become, they're being joined by something that has much more power and flexibility: the "smart card." A smart card is a plastic card that has the look and feel of a credit card--it's about the same size and shape-- but with one significant difference: a smart card has an embedded microprocessor. The microprocessor is capable of doing computer-like things such as running programs, processing input and output, and storing data. But unlike most computers, a smart card does not incorporate a display or a keyboard--in fact, it has no power supply. Because it needs a way to get input and display results, a smart card works in tandem with a card acceptance device (CAD), that is, a card reader or terminal. Both of these device types have slots into which a card is placed for reading. Card readers are connected to computers; terminals are themselves computers.

A smart card and smart card reader

A smart card microprocessor can be programmed and because of that, you can use smart cards to do things that you can't do with credit cards. For example, you can use a smart card to "pay-as-you-go." One application of that is using a smart card to pay bridge tolls. Here you purchase a card that has an initial monetary value. Each time you go through a toll booth, a scanner reads the current value of the card (the card is probably mounted on the dashboard of your car) and deducts the toll from the card's current value. When the current value of the card drops to a low or zero value, you buy another one or go to the appropriate people and have them add more value to the card.

A smart card can also be used to maintain personal records, for example, your medical records. Each time you visit a medical office, say your doctor's office, a clinic, or a hospital, the administrative staff updates your card to keep your records current. This can be particularly valuable in emergencies, when you might not be physically capable of communicating with medical personnel.

These are just two of an almost limitless number of possible applications for smart cards. Not only can a card be programmed for many different types of applications, but more than one application can be loaded onto a card. If these applications are coded using Java Card technology, the code and data for one application is protected from access (and possible damage) by the others. In Java terminology these applications are said to run in their own "sandbox."

In addition, smart cards can be reprogrammed. This is an important convenience to smart card issuers. For example, imagine that a bank has issued smart cards to over 500,000 of its customers. If the bank needs to update a program on these cards, it simply makes the update available for download on a computer attached to the card reader. The next time a bank customer swipes the card through the reader, the update is downloaded onto the card; the bank does not have to reissue any smart cards.

About Java Card Technology

Initially, smart card application development was essentially proprietary. Although all smart cards generally looked the same, each smart card's software was specific to the design of its embedded microprocessor. This usually meant that if company A manufactured smart cards, and company B manufactured smart cards, there was no generic way of coding applications that could run on cards produced by both manufacturers. As a result, smart card application development was limited to a relatively small group of developers who either worked for the smart card manufacturers or the smart card issuers.

Java Card technology provides an architecture for open application development for smart cards, using the Java programming language.

However in recent years, smart card application development has evolved so that it is no longer proprietary. Now smart card developers can produce applications that can run on cards from different manufacturers. Applications from different developers can run on the same smart card. This has opened up smart card development to independent application providers.

Java Card technology provides an architecture for open application development for smart cards, using the Java programming language. The technology can also be used to develop applications for other devices that have extremely small memory, such as subscriber identity module (SIM) cards for wireless phones. A SIM card is a smart card with a much smaller plastic substrate than credit-card sized smart cards. Typically, a SIM card has more memory than other types of smart cards such as bank cards.

Java Card technology comprises a set of specifications for the following:

A virtual machine 1. The virtual machine specification describes the characteristics of the virtual machine for handling Java Card applications.

A runtime environment. The Java Card Runtime Environment (JCRE) specification details runtime behavior, such as how memory is managed or how security is enforced.

A Bit of Java Card History

Java Card 1.0 was initially proposed by engineers at Schlumberger. It consisted of a specification for APIs only. Later, other companies, such as Bull and Gemplus, joined Schlumberger to form the Java Card Forum. This is an industry consortium that works for the adoption of Java Card technology in the smart card industry. Later Sun Microsystems worked with the Java Card Forum and other representatives of the smart card industry to develop Java Card 2.0. This level of the technology included a JCRE specification.

Java Card 2.1.1, the most recent release of the technology, includes the API, virtual machine, and JCRE specifications. It is available for download.

Also available for download is the Java Card 2.1.1 Development Kit. The development kit provides an environment to test Java card applets, and a converter tool that prepares Java Card applets for downloading onto a smart card (or onto another device that implements Java Card 2.1 or higher). It also includes sample Java Card applets.

It's Time to Examine a Java Card Applet

Now that you've been introduced to smart cards and Java Card technology, it's time to look at a Java Card applet. By examining the details of the code in an applet, you'll should be able to get started coding your own applets.

The Java Card applet illustrated in this article is one of the sample Java Card applets in the Java Card 2.1.1 development kit.

Anatomy of a Java Card Applet

Wallet is a sample Java card applet that is packaged in the Java Card 2.1.1 development kit. You can find the source code file, Wallet.java, in the samples directory. Or click here to see the source code for the Wallet applet. The Wallet applet turns a smart card into an electronic version of a wallet. Like a wallet, a smart card with the Wallet applet can hold money, although here it's a digital version of money. The applet can add money to or subtract money from the wallet. It can also indicate the current amount of money in the wallet. Of course a wallet should be protected so that only its owner (or someone else who is similarly authorized) can get to the money. Because of this, the Wallet applet also includes a security mechanism that requires each user to enter a Personal Identification Number (PIN). Only users who enter authorized PINs can direct money-related requests to the applet.

The following sections step you through the Wallet source code in detail.

Declaring the Package

In the same way that you can bundle related Java classes and interfaces into a package, you can bundle related Java Card applets into a package. You do this by specifying a package statement at the beginning of the source file for the applet. The format of the package statement and the name you use for the package follow Java language conventions. In fact, Java Card technology follows Java language conventions for all identifiers. The following statement specifies Wallet as a member of the com.sun.javacard.samples.wallet package:

package com.sun.javacard.samples.wallet;

Importing the Java Card Framework

Java Card technology defines a set of classes and interfaces for Java Card application programming. These classes and interfaces are provided in various packages. One of the packages, javacard.framework, defines classes and interfaces that are essential for developing Java Card applets, such as the base Applet class. The following statement imports the javacard.framework package:

import javacard.framework.*;

See Java Card Classes Used in the Wallet Applet for a description of the classes in the javacard.framework package that are used in the Wallet applet.

Extending the Base Applet Class

The javacard.framework package defines the class javacard.framework.Applet, which is the base class for all Java Card applets. javacard.framework.Applet defines the methods that a Java Card applet uses to communicate with the JCRE. All Java Card applets extend from the base class, as is the case for the Wallet applet:

public class Wallet extends Applet

The Reference section of this article contains a list of all the javacard.framework.Applet Methods Used in the Wallet Applet.

Declaring Constants

The Wallet applet declares various constants. Some constants are one-byte values in the header of command APDUs (Application Protocol Data Units). APDUs are packets of data that are exchanged between the CAD and a smart card. APDUs are the standard means of communication for smart cards. There are two types: command APDUs, which specify an operation to be performed by a smart card; and response APDUs, which contain the smart card's response (status and optionally, data) to an operational request.

What's an APDU?

Java Card technology is modeled after a smart card specification standard, ISO7816. The standard specifies that communication between a host application and a smart card is done through Application Protocol Data Units (APDUs). An APDU is a packet of data that conforms to a specific format. There are two types of APDUs: command APDUs and response APDUs.

A command APDU starts with a header and is optionally followed by a body. The header contains fields that specify an operation to be performed by a smart card. The body includes any data that accompanies the request; it also indicates the maximum number of data bytes expected in response to the command.

A response APDU optionally begins with a body that contains any data returned in th response. The response APDU ends with two mandatory bytes that specify the processing state of the card.

See APDU formats for an illustration of the command and response APDU formats.

In Java Card technology, the host application sends a command APDU, and a Java Card applet responds with a response APDU. (In fact, a Java Card applet sits idle until it receives a command APDU.) However the communication is not directly host application-to-Java Card applet. Instead the JCRE acts as an intermediary. The command APDU is transmitted to the JCRE, which sends it to the appropriate Java Card applet for processing. After processing the APDU, the Java Card applet transmits a response APDU to the JCRE, which sends it to the host application.

If you refer to APDU Formats, you'll notice that the first byte of a command APDU is the CLA byte. CLA stands for class of instruction. The value of the CLA byte identifies an APDU category. ISO7816 demands a specific value for the CLA byte for only one category of APDU commands -- the SELECT APDU command. The value of the CLA byte for a SELECT APDU command must be 0. Although ISO7816 does not demand a specific value for other APDU command categories, it does identify a set of requirements that these values must meet. So for APDU command categories other than the SELECT APDU command, you're free to select a value for the CLA byte as long as the value is compliant with the ISO specification. For the Wallet applet, the hexadecimal value 0xB0 is used to identify the PROCESS category of APDU commands. This means that for processing operations such as credit and debit, the CLA byte in the applicable APDU commands have a hexadecimal value 0xB0.

The second byte of a command APDU is the INS byte. This byte identifies a specific instruction, for example, a specific type of processing request. You're free to select the values for the INS byte. For the Wallet applet, the hexadecimal values 0x20, 0x30, 0x40, and 0x50 specify instructions for PIN verification, credit, debit, and get the current balance, respectively.

Other constants set limits on the credit and debit processing done by the applet. The constant MAX_BALANCE sets a maximum balance for the electronic wallet of $32,767 (that is, hexadecimal 0x7FFF), and the constant MAX_TRANSACTION_AMOUNT sets a maximum value for credit and debit transactions of $127. There are also constants that control the maximum number of times an invalid PIN can be entered before PIN entry is blocked (3), and the maximum size of the PIN (8).

The final set of constants declared in the Wallet applet are status word values that are returned by the applet in certain circumstances, such as when PIN verification fails. As part of the APDU protocol, these constants are passed from the applet to the JCRE, and on to the host application.

// signal that the PIN verification failed
final static short SW_VERIFICATION_FAILED = 0x6300;
// signal the 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_AMOUNT 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 the balance becomes negative
final static short sw_negative_balance = 0x6a85;

Declaring Member Variables

The Wallet applet declares two member variables that are used to contain values for specific objects. The variable pin is an OwnerPIN object that holds the user's PIN value. OwnerPIN is a class defined in the javacard.framework package. The class provides methods for performing PIN operations, such as updating or verifying a PIN. The variable balance indicates the current amount of money in the electronic wallet.

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

Specifying a Constructor

An instance of a Java Card applet is created through the applet's install method (see Installing the Applet for details). When the install method runs, it invokes a constructor. The constructor does three things: it creates an OwnerPIN object, initializes the object, and registers the applet instance. The constructor is declared private. This means that no other class can instantiate the Wallet applet.

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

Notice the comment about memory allocation. Although not a requirement, it's recommended that all objects created in a Java card applet should be instantiated in the applet's constructor. This is to avoid running out of memory at run time.

Also notice that the OwnerPIN instantiation is specified with two parameters: the maximum number of incorrect tries before the the PIN is blocked ( PIN_TRY_LIMIT) and the maximum PIN size ( MAX_PIN_SIZE). Recall that the PIN_TRY_LIMIT constant is 3 and the MAX_PIN_SIZE constant is 8. The update method is defined in the OwnerPIN class. It sets a new value for the PIN, and sets the maximum number of PIN tries to the value of PIN_TRY_LIMIT.

Before an instance of a Java Card applet can run, it needs to be registered with the JCRE. The Wallet constructor does this by calling register, a method defined in javacard.framework.Applet.

Identifying Applets

The ISO7816 standard specifies that each smart card application must be uniquely identified by an application identifier (AID). The AID is an array of bytes. The first five bytes is a resource identifier (RID); the remaining bytes (which can range from zero to eleven bytes) is a proprietary identifier extension (PIX). ISO assigns AIDs to requesters such as smart card manufacturers; the requesters are free to choose their own RIDs.

In Java Card technology, AIDs are used to identify Java Card applets as well as packages of Java Card applets. When someone inserts a smart card that implements Java Card technology into a card acceptance device, the application running on the device sends a command to the card. The command identifies an operation to be performed as well as the AID of the applet to perform the operation.

Installing the Applet

The javacard.framework.Applet class defines a static method, install. The install method is like the main method in a Java program. It's the main entry point into the applet. The JCRE calls this method to create an instance of a Java Card applet and give it control. All Java Card applets must implement the install method. What the implementation does is up to the applet designer. However at the very least, the implementation should call the applet's constructor to create and initialize an instance of the applet. It's also typical for the constructor to register the instance. And that's the case in the Wallet applet (see Specifying a Constructor). Because there is a call to the register method in the applet's constructor, each instance of Wallet registers itself with the JCRE when the instance is initialized. How does the JCRE know which applet to install and register? See Identifying Applets for the answer.

bArray is an array of type byte that contains installation parameters.

bOffset is a variable of type short that contains the starting offset into the array.

bLength is a variable of type byte that contains the length, in bytes, of the parameter data in the array.

The installation parameters usually include applet configuration values such as the size of internal files, and applet initialization values such as an initial identification. But where do these installation parameters come from? The answer is that usually the installation parameters are loaded onto the smart card when the applet is installed. Of course, for an applet to correctly process the installation parameters, it needs to know the parameter content and format. Or more to the point, the designer of the applet needs to understand the content and format of the installation parameters and factor that into the applet's processing logic.

Selecting and Deselecting the Applet

After it's initialized, an applet waits in a suspended state until the JCRE specifically selects it. The selection process is triggered when the JCRE receives a SELECT APDU command from the host application. In general, a host application communicates with a Java Card applet through APDUs (see the box What's an APDU?). When the JCRE receives an APDU, it checks to see if the APDU header specifies a SELECT APDU command.

As indicated in APDU Formats, the header of a SELECT APDU command has a standard value. If the header value indicates that this is a SELECT APDU command, the JCRE compares the AID valuein the data field to a list of AIDs that are registered for the smart card. If the JCRE finds a match, it calls the select method for that applet. This is a method defined in the javacard.framework.Applet class. The select method tells the JCRE if the applet is ready to process requests, by returning a true value. If the applet is not ready to accept processing requests, the select method returns a false value. The JCRE then sends a Response APDU to the host application indicating whether the selection was successful or unsuccessful. See APDU Formats, for the format of the Response APDU sent in response to a SELECT APDU command.

The criteria an applet uses to determine whether it should return true or false depends on the applet's design. For the Wallet applet, the select method checks to see if the PIN is blocked (because the pin try limit has been reached). If the PIN is blocked, the select method returns false, otherwise it returns true.

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

When another applet is selected, that is, an applet with another AID, the JCRE calls the current applet's deselect method. Like the select method, the deselect method is defined in the javacard.framework.Applet class. The deselect method does any necessary cleanup before the JCRE gives the newly selected applet control. In the Wallet applet, the deselect method resets a flag to indicate that the PIN is no longer validated.

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

Processing Requests

After an applet is selected and returns true to the JCRE, all incoming requests from the host application are sent to the applet's process method for processing. The process method is another method defined in javacard.framework.Applet.

public void process(APDU apdu) {

Notice that the process method accepts one parameter, an APDU object. The APDU object is an instance of the javacard.framework.APDU class. The JCRE creates an APDU object as a way to communicate a command APDU to a Java Card applet and to receive a response APDU from the Java Card applet. It's important to note that references to an APDU object are allowed only within a method, that is, as a parameter to the method or stored in a local variable. This is to protect against the possibility of one Java Card applet accessing APDU data that belongs to another Java Card applet.

As mentioned in Selecting and Deselecting the Applet, a host application communicates with a Java Card applet through APDUs. When the JCRE receives a command APDU, it writes the APDU header into an internal byte array called the APDU buffer. The APDU header comprises the first five bytes of the APDU, that is, the CLA and INS bytes, plus three other bytes, P1, P2, and Lc that are described in APDU Formats. The APDU buffer is encapsulated in the APDU object that the JCRE passes to the process method. To process an APDU, an applet must first get a pointer to the APDU buffer. It does this by using getBuffer, a method defined in the APDU class:

byte buffer[] = apdu.getBuffer();

Examines the Header

The process method examines the first two bytes of the APDU header, the CLA byte and INS byte. If the value of the CLA byte is 0 and the value of the INS byte is 0xA4, it indicates that this is the header of a SELECT APDU command. In this case, the process method returns control to the JCRE:

Notice the use of the constants ISO7816.OFFSET_CLA and ISO7816.OFFSET_INS. The ISO7816 interface in the Java Card API defines various constants for use by Java Card applets. A number of these constants are intended for use as indexes into the APDU header; these constants begin with OFFSET. The constants ISO7816.OFFSET_CLA and ISO7816.OFFSET_INS are the indexes for the CLA and INS bytes, respectively.

The process method then checks the CLA byte to see if it has the value Wallet_CLA. Recall that in the Wallet applet, the hexadecimal value 0xB0 is used to identify the PROCESS category of APDU commands, and that the constant Wallet_CLA is the value 0xB0. If the CLA byte does not have the value Wallet_CLA, the request can't be processed by the Wallet applet, and so the process method throws an exception with a constant that is used in the status word of the response APDU:

The constant ISO7816.SW_CLA_NOT_SUPPORTED is defined in the IS07816 interface of the Java Card API. ISO7816 interface constants that begin with SW are used in the status word of a response APDU.

Calls the appropriate method to process the request

If the CLA byte of the APDU header indicates a PROCESS category of APDU command, the process method checks the INS byte to determine the type of PROCESS category request. It then calls the appropriate method in Wallet, as follows, to handle the request:

The credit method in the Wallet applet credits an amount to the current balance. The method is called with one parameter: an APDU object. The APDU object encapsulates an APDU buffer that contains the CREDIT command APDU. The amount to be credited to the current balance is in the data field of the APDU.

private void credit(APDU apdu) {

The method begins by checking the PIN for validation. Recall that the variable pin is an OwnerPIN object. The method isValidated is defined in OwnerPIN; the method returns a true value if the PIN is currently validated, that is, a valid PIN was presented since the last card reset, or since the last call to the reset method. If the PIN is not validated, that is, ! pin.isValidated() returns true, the credit method throws an exception with a constant that is returned in the status word of the response APDU:

The APDU buffer initially contains the header of the CREDIT APDU command. As illustrated in APDU Formats, the Lc byte of the APDU header indicates the number of bytes in the data field. The credit method uses the IS07816 interface constant OFFSET_LC to access the Lc byte in the APDU buffer:

// 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 from the offset
// ISO7816.OFFSET_CDATA following the 5 header
// bytes.

At this point, the credit method is ready to get the incoming data, that is, the amount to be credited to the current balance, and put it in the APDU buffer. It does this by calling setIncomingAndReceive, a method defined in the APDU object. setIncomingAndReceive gets as many bytes of data as will fit into the APDU buffer, and returns the number of bytes it reads. For the Wallet applet, setIncomingAndReceive should read one byte of data. That's because the Lc byte, which indicates the number of bytes in the data field, has the value 1. The credit method checks this. If the number of bytes read is not 1, the method throws an exception with a constant that is returned in the status word of the response APDU:

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 ( ( numBytes != 1 ) || (byteRead != 1) )
ISOException.throwIt(ISO7816.SW_WRONG_LENGTH);

With the credit amount available in the APDU buffer, credit performs the core part of its processing. It:

Gets the credit amount from the APDU buffer

Checks that the credit amount does not violate the maximum transaction limit specified by the MAX_TRANSACTION_AMOUNT constant, or is less than 0

Checks that the new balance (with the credit amount added) doesn't exceed the maximum balance limit specified by the constant MAX_BALANCE

Notice that credit uses another ISO7816 interface constant, OFFSET_CDATA as an index to the data field of the APDU buffer. Notice too that the method throws an exception with a constant if the transaction limit or the balance limit is exceeded. The constant is returned in the status word of the response APDU.

After the credit method successfully completes its processing, it returns control to the JCRE. The JCRE then sends a response APDU to the host application that contains the status word value 0x9000; this indicates that the CREDIT APDU command was successfully processed.

Go to Part 2

1 As used in this document, the terms "Java virtual machine" or "JVM" mean a virtual machine for the Java platform.