Understanding Java Card 2.0

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

This article begins with an overview of smart cards and a brief review of ISO 7816, the smart card standard. Given the background on smart cards in previous Java Developer columns, this installment will begin with an answer to the question, "What is a Java Card?" and an overview of the Java Card system architecture. Next, we'll focus on the many issues specific to the Java Card, including the Java Card lifecycle; the Java Card 2.0 language subset and API library classes; and Java Card security. Then we'll discuss the Java Card runtime environment and show how a Java Card runs. We'll close with an illuminating example: An electronic wallet application written just for the Java Card.

From here on, all references to Java Card implicitly refer to the Java Card 2.0.

What is a smart card?

Identical to the size of a credit card, a smart card stores and processes information through the electronic circuits embedded in silicon in the plastic substrate of its body. There are two basic kinds of smart cards: An intelligent smart card contains a microprocessor and offers read, write, and calculating capability, like a small microcomputer. A memory card, on the other hand, does not have a microprocessor and is meant only for information storage. A memory card uses security logic to control the access of memory.

All smart cards contain three types of memory: persistent non-mutable memory; persistent mutable memory; and non-persistent mutable memory. ROM, EEPROM, and RAM are the most widely-used memory for the three respective types in the current smart cards. Persistent memory is also called non-volatile memory. We will use the terms persistent and non-volatile interchangeably in this article.

ISO 7816 part 1-7, defined by International Standard Organization, contains a set of standards that covers various aspects of smart cards. ISO 7816 consists of:

  • Physical characteristics (part 1)

  • Dimensions and location of the contacts (part 2)

  • Electronic signals and Transmission protocols (part 3)

  • Inter-industry commands for interchange (part 4)

  • Application identifiers (Part 5)

  • Inter-industry data elements (Part 6)

  • Inter-industry commands for SCQL (Part 7)

The following diagram illustrates the physical characteristics of a smart card, which are defined in ISO 7816, part 1.

For more on ISO 7816 and smart cards, see "Smart cards: A primer."

Normally, a smart card does not contain a power supply, a display, or a keyboard. It interacts with the outside world using the serial communication interface via its eight contact points. The dimensions and location of the contacts are covered in part 2 of ISO 7816. This diagram shows the contacts on a smart card.

A smart card is inserted into a Card Acceptance Device (CAD), which may connect to another computer. Other terms used for the Card Acceptance Device are terminal, reader, and IFD (interface device). They all provide the same basic functions, namely to supply the card with power and to establish a data-carrying connection.

When two computers communicate with each other, they exchange data packages, which are constructed following a set of protocols. Similarly, smart cards speak to the outside world using their own data packages -- called APDU (Application Protocol Data Units). APDU contains either a command or a response message. In the card world, the master-slave model is used whereby a smart card always plays the passive role. In other words, a smart card always waits for a command APDU from a terminal. It then executes the action specified in the APDU and replies to the terminal with a response APDU. Command APDUs and response APDUs are exchanged alternatively between a card and a terminal.

The following tables illustrate command and response APDU formats, respectively. APDU structure is described in ISO 7816, part 4.

Command APDU
Mandatory HeaderConditional Body
CLAINSP1P2LcData fieldLe

The header codes the selected command. It consists of four fields: class (CLA), instruction (INS), and parameters 1 and 2 (P1 and P2). Each field contains 1 byte:

  • CLA: Class byte. In many smart cards, this byte is used to identify an application.

  • INS: Instruction byte. This byte indicates the instruction code.

  • P1-P2: Parameter bytes. These provide further qualification to the APDU command.

Lc denotes the number of bytes in the data field of the command APDU; Le denotes the maximum number of bytes expected in the data field of the following response APDU.

Response APDU
Conditional BodyMandatory Trailer
Data fieldSW1SW2

Status bytes SW1 and SW2 denote the processing status of the command APDU in a card.

What is a Java Card?

A Java Card is a smart card that is capable of running Java programs. The Java Card 2.0 specification was published at http://www.javasoft.com/javacard. It contains detailed information for building the Java Card virtual machine and application programming interface (API) in smart cards. The minimum system requirement is 16 kilobytes of read-only memory (ROM), 8 kilobytes of EEPROM, and 256 bytes of random access memory (RAM).

The system architecture on the Java Card is illustrated in the following figure.

As shown in the figure, the Java Card VM is built on top of a specific integrated circuit (IC) and native operating system implementation. The JVM layer hides the manufacturer's proprietary technology with a common language and system interface. The Java Card framework defines a set of Application Programming Interface (API) classes for developing Java Card applications and for providing system services to those applications. A specific industry or business can supply add-on libraries to provide a service or to refine the security and system model. Java Card applications are called applets. Multiple applets can reside on one card. Each applet is identified uniquely by its AID (application identifier), as defined in ISO 7816, part 5.

An important point to keep in mind is what smart cards are not: They are not personal computers. They have limited memory resources and computing power. Users should not think of Java Card 2.0 as simply a stripped-down version of the JDK.

The lifetime of a Java Card

The Java Card lifetime starts when the native OS, Java Card VM, API classes libraries and optionally, applets are burned into ROM. This process of writing the permanent components into the non-mutable memory of a chip for carrying out incoming commands is called masking.

Before it lands in your wallet, a Java Card needs to go through initialization and personalization. Initialization refers to loading general data into a card's non-volatile memory. This data is identical across a large number of cards and is not specific to an individual; an example might be the issuer or manufacture's name.

The next step, personalization, involves assigning a card to a person. It can occur through physical personalization or through electronic personalization. Physical personalization refers to embossing or laser engraving your name and card number on the plastic surface of a card. Electronic personalization refers to loading personal data into a card's non-volatile memory, for example, your personal key, name, and pin number.

Initialization and Personalization vary from vendor to vendor and issuer to issuer. In both, EEPROM (a type of non-volatile memory) is often used for storing data.

At this point, the Java Card is ready for use. You can get a Java Card from an issuer or buy it from a retailer. Cards sold by a retailer are general-purpose, in which case personalization is often omitted.

Now you can insert your Java Card into a reader and send APDU commands to the applets residing on the card or download more applets or data onto the card.

A Java Card remains active until it is expired or blocked due to an unrecoverable error.

Lifetime of a Java Card virtual machine

Unlike the Java virtual machine (JVM) in a PC or workstation, the Java Card virtual machine runs forever.

Most of the information stored on the card must be preserved even when the power is removed -- that is, when the card is removed from the reader. The Java Card VM creates objects in EEPROM to hold the persistent information. The execution lifetime of the Java Card VM is the lifetime of the card. When the power is not provided, the VM runs in an infinite clock cycle.

The lifetime of Java Card applets and objects

An applet's life starts when it is properly installed and registered with the system's registry table and ends when it is removed from the table. The space of a removed applet may or may not be reused, however, depending on whether garbage collection is implemented on the card. An applet on a card is in an inactive stage until it is explicitly selected by the terminal.

Objects are created in the persistent memory (for example, EEPROM). They could be lost or garbage-collected if other persistent objects do not reference them. However, it's a thousand times slower to write to EEPROM than to RAM.

Some objects are accessed frequently, and the contents of their fields need not be persistent. The Java Card supports transient (temporary) objects in RAM. Once an object has been declared as transient, its contents can not be moved back to the persistent memory.

Java Card 2.0 language subset

Java Card programs are, of course, written in Java. They are compiled using common Java compilers. Due to limited memory resources and computing power, not all the language features defined in the Java Language Specification are supported on the Java Card. Specifically, the Java Card does not support:

  • Dynamic class loading

  • Security manager

  • Threads and synchronization

  • Object cloning

  • Finalization

  • Large primitive data types (float, double, long, and char)

It's no surprise that keywords that support those features are also omitted from the language. VM implementors may decide to support 32-bit integer type or native methods for post-issuance applets if they are working on a more advanced smart card with more memory. Post-issuance applets are those applets that are installed on a Java Card after the card is issued to a card holder.

The Java Card 2.0 framework

Smart cards have been in the market for 20 years, and most of them are generally compatible with ISO 7816 Parts 1-7 and/or EMV. We've already looked at ISO 7816. What's EMV? The EMV standard, defined by Europay, MasterCard, and Visa, is based on the ISO 7816 series of standards with additional proprietary features to meet the specific needs of the financial industry. The Java Card Framework is designed to easily support smart card systems and applications. It hides the details of the smart card infrastructure and provides Java Card application developers with a relatively easy and straightforward programming interface.

The Java Card framework contains four packages:

Package NameDescription
javacard.frameworkThis is the core package on the card. It defines classes such as and , which are the fundamental building blocks for Java Card programs and , and , which provide runtime and system service to Java Card programs, such as APDU handling and object sharing
javacardx.framework This package provides an object-oriented design for an ISO 7816-4 compatible file system. It supports elementary files (EF), dedicated files (DF) and file-oriented APDUs as specified in ISO7816
javacardx.crypto and javacardx.cryptoEnc Those two packages support cryptographic functionality required in smart cards

Conforming to the Java naming convention, Java Cardx packages are extensions to the Java Card framework. It's not required that you support them on the card.

Java Card security

Java applets are subject to Java security restrictions, however, the security model of Java Card systems differs from standard Java in many ways.

The Security Manager class is not supported on Java Card. Language security policies are implemented by the virtual machine.

Java applets create objects that store and manipulate data. An object is owned by the applet that creates it. Even though an applet may have the reference to an object, it cannot invoke the object's methods, unless it owns the object or the object is explicitly shared. An applet can share any of its objects with a particular applet or with all applets.

An applet is an independent entity within a Java Card. Its selection, execution, and functionality are not affected by other applets residing on the same card.

How things work together inside a Java Card

Inside a Java Card, JCRE (Java Card Runtime Environment) refers to the Java Card virtual machine and the classes in the Java Card Framework. Each applet within a Java Card is associated with unique AID assigned by JCRE.

After an applet is correctly loaded into the card's persistent memory and linked with the Java Card Framework and other libraries on the card, JCRE calls the applet's install method as the last step in the applet installation process. A public static method, install, must be implemented by an applet class to create an instance of the applet and register it with JCRE. Because memory is limited, it's good programming practice, at this point, to create and initialize the objects the applet will need during its lifetime.

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

How to write a Java Card applet

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

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

package bank.purse;

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

import javacard.framework.*;

import javacardx.framework.*;

 

public class Wallet extends Applet {

  /* constants declaration */

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

  // code of CLA byte in the command APDU header

  final static byte Wallet_CLA =(byte)0xB0;

CLA identifies the application

  // codes of INS byte in the command APDU header

  final static byte Deposit = (byte) 0x10;

  final static byte Debit = (byte) 0x20;

  final static byte Balance = (byte) 0x30;

  final static byte Validate = (byte) 0x40;

INS specifies the application instructions

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

  final static byte PinTryLimit =(byte)0x03;

  // maximum size PIN

  final static byte MaxPinSize =(byte)0x04;

PIN object parameters

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

  final static short SW_NEGATIVE_BALANCE = (short) 0x6910;

Applet specific static word

  /* instance variables declaration */

  OwnerPIN pin;

  byte balance;

  byte buffer[];

// APDU buffer

 

  private Wallet() {

    // It is good programming practice to allocate

    // all the memory that an applet needs during its

    // lifetime inside the constructor

    pin = new OwnerPIN(PinTryLimit, MaxPinSize);

    balance = 0;

    register();

  } // end of the constructor

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

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

  public static void install(APDU apdu){

    // create a Wallet applet instance

    new Wallet();

  } // end of method

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

    public boolean select() {

    // reset validation flag in the PIN object to false

    pin.reset();

    // returns true to JCRE to indicate that the applet

    // is ready to accept incoming APDUs.

    return true;

  }// end of method

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

  public void process(APDU apdu) {

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

    // transfer incoming and outgoing APDU header

    // and data bytes between card and CAD

    buffer = apdu.getBuffer();

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

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

    // verify that if the applet can accept this

    // APDU message

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

      ISOException.throwIt

           (ISO.SW_CLA_NOT_SUPPORTED);

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

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

    switch (buffer[ISO.OFFSET_INS]) {

      case Balance:   getBalance(apdu); return;

      case Debit:   debit(apdu); return;

      case Deposit:   deposit(apdu);return;

      case Validate:    validate(apdu);return

      default:   ISOException.throwIt

             (ISO.SW_INS_NOT_SUPPORTED);

    }

}   // end of method

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

INS byte specifies the type of action needs to be performed

  private void deposit(APDU apdu) {

    // access authentication

    if ( ! pin.isValidated() )

      ISOException.throwIt (ISO.SW_PIN_REQUIRED);

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

    // field of the comamnd APDU

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

    // indicate that this APDU has incoming data and

    // receive data starting from the offset

    // ISO.OFFSET_CDATA

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

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

    // match the number in Lc byte

    if (byteRead != 1)

      ISOException.throwIt(ISO.SW_WRONG_LENGTh);

    // increase the balance by the amount specified in the

    // data field of the command APDU.

    balance = (byte)

      (balance + buffer[ISO.OFFSET_CDATA]);

    // return successfully

    return;

} // end of deposit method

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

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

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

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

  private void debit(APDU apdu) {

    // access authentication

    if ( ! pin.isValidated() )

      ISOException.throwIt(ISO.SW_PIN_REQUIRED);

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

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

    if (byteRead != 1)

      ISOException.throwIt(ISO.SW_WRONG_LENGTH);

    // balance can not be negative

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

      ISOException.throwIt(SW_NEGATIVE_BALANCE);

    balance = (byte)

        (balance - buffer[ISO.OFFSET_CDATA]);

} // end of method

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

  private void getBalance(APDU apdu) {

    // access authentication

    if ( ! pin.isValidated() )

      ISOException.throwIt(ISO.SW_PIN_REQUIRED);

    // inform system that the applet has finished processing

    // the command and the system should now prepare to

    // construct a response APDU which contains data field

    apdu.setOutgoing();

    // indicate the number of bytes in the data field

    apdu.setOutgoingLength((byte)1);

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

    buffer[0] = balance;

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

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

} // end of method

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

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

private void validate(APDU apdu) {

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

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

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

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

    // object to be true if the validation succeeds.

    // if user interface validation fails, PinException would be

    // thrown from method.

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

  } // end of method

} // end of class Wallet

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

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

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

Conclusion

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

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

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

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

Learn more about this topic

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