Applications running on Java smart cards are called applets. This chapter introduces the framework for writing applets. It is organized into seven sections. The first section provides an overall picture of how applets work within the JCRE. The remaining sections discuss the techniques of applet writing.
Applet features are described in more detail throughout the book. Chapters 8 and 9, for example, discuss APDU command handling and object sharing among applets.
A Java Card applet is a smart card application written in the Java programming language and conforming to a set of conventions so that it can run within the Java Card runtime environment (JCRE). A running applet in the JCRE is an instance of the applet class that extends from javacard.framework.Applet
. As with other persistent objects, an applet created on the card lives on through the entire lifetime of the card.[1] The Java Card platform supports a multiapplication environment. Each applet instance is uniquely identified by an AID (see Chapter 3 for more details on AIDs).
After the package(s) defining an applet have been properly loaded on a Java smart card and linked with other packages on the card, an applet's life starts when an instance of the applet is created and registered with the JCRE. The JCRE is a single-thread environment. This means that only one applet is running at a time. When an applet is first installed, it is in an inactive state. The applet becomes active when it is explicitly selected by a host application.
Applets, like any smart card applications, are reactive applications. Once selected, a typical applet waits for an application running on the host side to send a command. The applet then executes the command and returns a response to the host.
This command-and-response dialogue continues until a new applet is selected or the card is removed from the card acceptance device. The applet remains inactive until the next time it is selected. Applet execution states are illustrated in Figure 7.1.
The communication between an applet and a host application is achieved through exchanging APDUs, as illustrated in Figure 7.2. An APDU contains either a command or a response message. A host application sends a command to an applet and the applet returns a response. (See chapter 2 for more information on APDUs.)
When the host application wants to select an applet to run, it sends an APDU that specifies the SELECT command and the AID of the requested applet. The JCRE searches its internal table for an applet whose AID matches the one specified in the command. If a match is found, the JCRE selects that applet to run. All subsequent APDUs (including the SELECT APDU) are forwarded to the current applet until a new applet is selected.
Every applet is implemented by creating a subclass of the class javacard.framework.Applet
. The JCRE invokes the methods install
, select
, process
, or deselect
, which are defined in the base Applet
class, when it wants to install, select, or deselect the applet or to ask the applet to process an APDU command.
Methods in Table 7.1 are listed in the order in which they are invoked by the JCRE during applet creation and execution. The JCRE calls the install
method to create an applet instance. The applet instance is registered with the JCRE, using one of the two register
methods.
Table 7.1. Methods in the class javacard.framework.Applet
public static void
|
The JCRE calls this static method to create an instance of the |
|
This method is used by the applet to register this applet instance with the JCRE and to assign the default AID in the CAP file to the applet instance. |
protected final void
|
This method is used by the applet to register this applet instance with the JCRE and to assign to the applet instance the AID specified in the array |
public boolean
|
The JCRE calls this method to inform the applet that it has been selected. |
public abstract void
|
This JCRE calls this method to instruct the applet to process an incoming APDU command. |
public void
|
The JCRE calls this method to inform the currently selected applet that another (or the same) applet will be selected. |
When receiving a SELECT APDU, the JCRE first checks whether an applet is already selected. If so, the JCRE deselects the current applet by invoking the deselect
method. In the deselect
method, the applet performs any cleanup or bookkeeping work before it becomes inactive. Then the JCRE selects the new applet by invoking the select
method. The applet performs any initialization necessary in the select
method.
After successful selection, each APDU (including the SELECT APDU) is delivered to the active applet via a call to its process
method. The process
method is an essential method in the applet class. It processes APDU commands and thus provides an applet's functions.
The methods install
, select
, deselect
, and process
are applet entry point methods. They are invoked by the JCRE at the appropriate state of applet creation and execution. The base Applet
class provides only the default behavior for these methods. An applet needs to override some or all of these methods to implement its functions. The details of each of these methods are specified in the remainder of this chapter.
The install
method is typically called by the JCRE as the last step during applet installation to create an applet instance-a runnable applet (applet installation is discussed in chapter 3). The install
method is similar to the main
method in a Java application. The arguments to the install
method carry the applet installation parameters. They are analogous to command-line arguments supplied to the main
method.
The install
method creates an applet instance by using the new
operator followed by a call to the applet's constructor. In the constructor, an applet typically performs the following tasks:
Creates objects that the applet needs during its lifetime
Initializes objects and the applet's internal variables
Registeres the applet instance with the JCRE by calling one of the two register
methods defined in the base Applet
class
Applet registration marks the beginning of the applet's lifetime. An applet must register with the JCRE so that it can be selected and set to run by the JCRE.
The following code shows an example of creating a wallet applet by using the default constructor.
public class WalletApp extends Applet{ private Log transaction_log; private byte[] wallet_id; private byte wallet_balance; public static void install (byte[] bArray, short bOffset, byte bLength) { new WalletApp(); } private WalletApp() { // create a transaction log with the specified number // of transaction records transaction_log = new Log(TRAN_RECORD_NUM); // create a byte array to store the wallet ID wallet_id = new byte[ID_LENGTH]; // initialize the wallet balance wallet_balance = INITIAL_BALANCE; // register the applet instance with the JCRE register(); } }
Alternatively, an applet can define a constructor that takes the installation parameters.
public walletApp(byte[] bArray, short bOffset, byte bLength) {...}
The installation parameters provide additional data for initializing and personalizing the applet. Processing the installation parameters is explained in Section 7.3.3.
On successful return from the install
method, the applet is ready to be selected and to process the upcoming APDU commands. Only one instance of an applet can be successfully created and registered from one invocation of the install
method. If the JCRE wants to create multiple instances of the same applet, each instance is created with a separate invocation of the install
method.
If a failure occurs during the install
method and prior to the successful invocation of the register
method, the JCRE will perform necessary cleanup to reclaim the card resources when it gets back control. The JCRE deletes the applet instance as well as the other objects created during the install
method and recovers the previous JCRE state. It is not necessary to set up a transaction in the install
method, since the JCRE ensures that the install
method is transactional. Applet registration signals the successful end of the transaction. Therefore, it is important to register the applet as the last step during applet creation. If any error occurs after the register
method, the applet will remain registered but might be left in a crippled state.
Notice that the install
method in the base Applet
class is simply a prototype. An applet must define an install
method of the same prototype.
Although objects and arrays can be created at any point in the execution of an applet, it is recommended that, when possible, such allocations occur only during the initialization of the applet. Any objects that might be required during execution of an applet should be preallocated in the constructor, to ensure that the applet will never fail due to lack of memory.
The constructor is invoked inside the install
method. Thus, if the JCRE detects resource shortage and is unable to allocate memory space for the applet during object creation or during some other resource allocation processing, the JCRE will delete the applet and reclaim all memory space. In this way, no partially created applet will be left behind in an unrunnable state.
However, an applet should not create more objects than it needs, since the memory occupied by unused objects cannot be reused or shared by other applets or the JCRE.
To register an applet with the JCRE, you use one of the two register
methods provided in the base Applet
class.
protected final void register()
or
protected final void register (byte[] bArray, short bOffset, byte bLength)
The register
method has two functions. First, it stores a reference to the applet instance with the JCRE. Second, it assigns an AID to the applet instance. Recall from Chapter 3 that each applet instance on the card is uniquely identified by an AID. The CAP file that defines the applet classes contains a default AID. However, an applet may choose to have an AID different from the default one. The default AID can be supplied in the installation parameters.
The first register
method (the one with no arguments) registers the applet with the JCRE using the default AID from the CAP file. The second register
method (with arguments) registers the applet instance with the JCRE using the AID specified in the argument bArray
. The argument bOffset
specifies the starting offset in bArray
, and bLength
specifies the AID length in bytes.
Typically, during applet installation, the installation parameters are sent to the card along with the CAP files that define an applet. The JCRE then provides the installation parameters to the applet via the arguments to the install
method. The install
method accepts three arguments:
byte[] bArray
—. Array containing installation parameters
short bOffset
—. Starting offset in bArray
byte bLength
—. Length in bytes of the parameter data in bArray
The content and format of the installation parameters are defined by the applet designers or the card issuers. Often, they contain applet configuration parameters and applet initialization values. Configuration parameters can be used to specify the size of an internal file, an array, and so on. In this way, the applet can allocate adequate memory to support anticipated processing while avoiding memory waste. Applet initialization values, for example, can specify the initial balance, the card holder's ID, and the account number in an electronic wallet. Another common use of the installation parameters is to supply an AID other than the default one in the CAP file. For example, suppose that two wallet applet instances are needed: one for personal use and the other for business. In such a case, the JCRE must invoke the applet's install
method twice. Each time, a wallet applet instance is created with a unique AID.
Suppose that the designer of the wallet applet specifies that the installation parameter byte array consist of the following fields:
A 1-byte binary value specifying the number of records in the transaction log.
A fixed-size array of 4 bytes specifying the wallet ID.
One byte containing the initial wallet balance.
One byte specifying the size of the next subarray.
A variable-size array of bytes specifying the AID for this applet instance. If this array is empty, the applet uses the default AID from the CAP file.
To create a wallet applet for personal use with the default AID, the installation parameters might be the bytes [0×10, 0×1, 0×2, 0×3, 0×4, 0×32, 0], which would be interpreted by the applet as
number of transactions in the transaction log = 0×10 = 16
wallet ID = [0×1, 0×2, 0×3, 04]
initial balance = 0×32 = 50
AID = the default AID from the CAP file
To create a wallet instance to handle business expense with an AID other than the default one, the installation parameters might be the bytes [0×10, 0×4, 0×3, 0×2, 0×1, 0×64, 0×F, 'B', 'A', 'N', 'K', '_', 'w', 'a', 'l', 'l', 'e', 't', '_', 'B', 'I', 'S'], which would be interpreted by the applet as
number of transactions in the transaction log = 0×10 = 16
wallet ID = [0×4, 0×3, 0×2, 0×1]
initial balance = 0×64 = 100
AID = ['B', 'A', 'N', 'K', '_', 'w', 'a', 'l', 'l', 'e', 't', '_', 'B', 'I', 'S']
The following code demonstrates how the wallet applet processes the installation parameters in the constructor:
private WalletApp(byte[] bArray, short bOffset, byte bLength) { // create a transaction log and specify the maximum number // of log records // max_record_num = bArray[bOffset] transaction_log = new Log(bArray[bOffset++]); // set the wallet ID wallet_id = new byte[ID_LENGTH]; Util.arrayCopy(bArray, bOffset, wallet_id, (byte)0, ID_LENGTH]); // advance bOffset by ID_LENGTH of bytes bOffset += ID_LENGTH; // initialize the wallet balance wallet_balance = bArray[bOffset++]; // check the AID byte AID_len = bArray[bOffset++]; if (AID_len == 0) { // register the applet instance with the JCRE // using the default AID this.register(); } else { // register the applet instance with the JCRE // using the AID specified in the installation parameters. // AID bytes in the bArray start from the index bOffset // and consist of the AID_len number of bytes this.register(bArray, bOffset, AID_len); } }
The content of bArray
does not belong to the applet. For security reasons, the JCRE clears the array on return from the install
method. If the applet desires to preserve any of these data, it should copy the data into its own object. In the example, the wallet ID bytes in bArray
are copied into the field wallet_id
.
The Java Card platform supports installation parameters of up to 32 bytes. Thus, the maximum value of bLength
is 32. In chapter 8 you will see that the JCRE employs a buffer to transmit APDUs. The minimum size of the APDU buffer is 37, including 5 bytes of header and 32 bytes of data. The number 32 is chosen as the maximum size of the installation parameters so that they can be transported in the buffer with one APDU I/O.
After a successful return from the install
method, simple applets might be fully ready to function in their normal role. More complex applets might need further personalization information before they are ready to execute normally. Such information might not all be available at applet creation time or might exceed the capacity of the installation parameters (32 bytes). In this case, a separate scheme (specified by applet designers or issuers) might be required to allow an applet to complete personalization in the process
method. In such a scheme, the applet needs to set internal state variables and is responsible for keeping track of these state transitions. To receive personalization information, the applet exchanges APDUs with the host.
An applet remains in a suspended state until it is explicitly selected. Applet selection occurs when the JCRE receives a SELECT APDU whose data match the AID of the applet. The JCRE informs the applet of its selection by invoking its select
method.
In the select
method, the applet can check whether its conditions for selection have been met, and if so, it can set internal variables and states necessary to handle subsequent APDUs. The applet returns true
from the call to the select
method if it is ready to accept incoming APDUs via its process
method, or it can decline to be selected by returning false
or by throwing an exception.
If the selection fails, the JCRE returns the status word 0×6999 to the host. If the select
method returns true
, the SELECT APDU command is then supplied to the applet in the subsequent call to its process
method so that the applet can respond to the host with applet-related information. For example, the wallet applet might return the wallet issuer's identification number, currency conversion information, or other parameters. The host might need this information to start DEBIT or CREDIT transactions. Applet designers or issuers are free to define the content and the format of the response data.
The select
method in the base Applet
class simply returns true
. An applet can override this method and define the actions required during selection.
The SELECT APDU command is the only APDU command that is standardized on the Java Card platform. It ensures interoperable applet selection on various Java Card platform implementations. The APDU format is depicted in Table 7.2. The data portion of the SELECT APDU contains an applet AID, which is between 5 and 16 bytes in length. For an applet to be selected, the entire data field of the APDU must match the AID of the applet.
On receiving an APDU, the JCRE decodes its header (CLA, INS, P1, and P2) to determine whether it is an applet selection command, and if so, whether the AID in the APDU data matches that of an applet on the card. A successful applet selection involves deselecting the current applet, selecting the new applet, and sending the SELECT APDU to the new applet's process
method. If the APDU is not for applet selection, the JCRE delivers it to the current applet for processing. In any case, if an error occurs during selection, the JCRE flags the error by returning the status word 0×6999 to the host, and no applet becomes selected on the card. Processing the SELECT APDU is illustrated in Figure 7.3.
Normally, applets become selected only via a successful SELECT command. However, some smart card systems require a default applet that is implicitly selected after every card reset.
To select a default applet, the JCRE calls the default applet's select
method and marks it as the currently selected applet. Because no SELECT APDU is required, the applet's process
method is not called subsequently during selection. If the default applet's select
method throws an exception or returns false
, no applet is selected until the next SELECT APDU is processed.
Default applet selection is an optional JCRE feature. When supported, a JCRE implementation should devise a mechanism for specifying the default applet.
Before a new applet is selected, the JCRE deactivates the current applet by calling its deselect
method. It is possible that the newly selected applet is the same as the current applet. In this case, the JCRE deselects it anyway and then reselects it.
The deselect
method allows the applet to perform any cleanup operations to prepare itself to go “off stage” and to enable another applet to execute. The default implementation in the class Applet
is an empty method. An applet should override this method for any required cleanup operations. For example, the wallet might need to reset the security condition or the transaction state, which is valid only during one selection period.
The deselect
method might fail. Even so, the current applet is deselected and a new applet is selected despite the result of executing the deselect
method. The JCRE also ignores any exceptions thrown from the deselect
method.
Furthermore, on reset or power loss, the applet is automatically deselected by the JCRE without its deselect
method being called. Therefore, an applet cannot always rely on the cleanup operations in the deselect
method.
When receiving an APDU command, the JCRE calls the current applet's process
method. In the process
method, an applet is expected to perform a function requested in the APDU. The process
method in the base Applet
class is an abstract method. An applet must directly or indirectly override this method. Usually the process
method is implemented as a dispatcher. On receiving an APDU command, the method decodes the APDU header and calls a service method to execute the requested function.
The JCRE encapsulates the APDU in the argument to the process
method, apdu
(an instance of the class APDU). The applet invokes methods on the apdu
object to receive and to return the APDU data. Handling APDU commands in an applet is covered thoroughly in Chapter 8.
There are two other methods in the Applet
class: selectingApplet
and getShareableInterfaceObject
.
The traditional smart card system is file system oriented. Application data are stored in files. A file must be selected before any action is performed on the data in the file. Readers who are familiar with ISO 7816 commands will recognize that the SELECT APDU in Table 7.2 is the ISO command select DF (dedicated file) by name. The JCRE can determine whether the command is for applet selection by matching the data in the command with the AID of any applet on the card (see Figure 7.3).[2] Because all APDUs are forwarded to the currently selected applet's process
method, the applet calls the selectingApplet
method to distinguish whether the SELECT APDU command is used to select this applet itself or whether it is attempting to select a DF of this applet. The selectingApplet
method returns true
if the APDU selects this applet. Otherwise, it returns false
.
The getShareableInterfaceObject
method is intended for object sharing among applets. It is invoked by the JCRE when another applet requests a shareable interface object from this applet. This method is further described in chapter 9 in the coverage of the applet firewall and object sharing.
18.216.123.120