Writing a Java Card Applet, Part 2

By Ed Ort, Release 2.1.1, January 2001

This section continues the Processing Requests discussion started in Part 1 of this article.

Processing Requests, continued

The last steps to processing the request include:

Debit an Amount from the Current Balance

The debit method in the Wallet applet debits an amount from the current balance. As is the case for the credit method, the debit method is called with one parameter: an APDU object. The APDU object encapsulates an APDU buffer that contains the DEBIT command APDU. The amount to be debited from the current balance is in the data field of the APDU.

private void debit(APDU apdu) {

The code in the debit method is similar to that in the credit method. Both methods:

  • Check the PIN for validation
  • Get a reference to the APDU buffer
  • Access the Lc byte in the APDU buffer to determine the number of bytes of incoming data
  • Read the incoming data into the APDU buffer
  • Check that the number of bytes read into the APDU buffer is the same as the value of the Lc byte
  • Get the data from the APDU buffer
  • Check that the data amount does not violate the maximum transaction limit specified by the MAX_TRANSACTION_AMOUNT constant, or is less than 0

For more details about these steps, see Credit an Amount to the Current Balance.

Where debit differs from credit is that the data in the APDU reflects the amount to be debited from the current balance (as opposed to credited to the balance). After the debit method performs the steps above, it subtracts the debit amount from the current balance and checks to ensure that the new balance isn't less than 0. Here is body of the debit method:

// access authentication

if ( ! pin.isValidated() )
ISOException.throwIt
(SW_PIN_VERIFICATION_REQUIRED);

byte[] buffer = apdu.getBuffer();

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

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

if ( ( numBytes != 1 ) || (byteRead != 1) )
ISOException.throwIt
(ISO7816.SW_WRONG_LENGTH);

// get debit amount
byte debitAmount =
buffer[ISO7816.OFFSET_CDATA];

// check debit amount
if ( ( debitAmount > MAX_TRANSACTION_AMOUNT)
||  ( debitAmount < 0 ) )
isoexception.throwit
(sw_invalid_transaction_amount);

// check the new balance
if ( (short)( balance - debitamount ) < (short)0 )
isoexception.throwit(sw_negative_balance);

balance = (short) (balance - debitamount);

} // end of debit method

As is the case for credit method, the JCRE indicates successful processing of the command APDU by sending a response APDU to the host application that contains the status word value 0x9000.

Get the Current Balance

The getBalance method in the Wallet applet returns the value of the current balance. The method is called with one parameter: an APDU object. The APDU object encapsulates an APDU buffer that contains the GET BALANCE command APDU. The value of the current balance is returned in the data field of the GET BALANCE response APDU.

private void getBalance(APDU apdu) {

The getBalance method first gets a reference to the APDU buffer (for more details, see Get a Reference to the APDU buffer):

byte buffer[] = apdu.getBuffer();

Unlike the credit and debit methods that read incoming data in a command APDU and then process it, the getBalance method does its processing (that is, gets the current balance) and then writes data for inclusion in a response APDU. It does this by first calling the APDU method setOutgoing. This tells the JCRE that the Java Card applet wants to send a response. The setOutgoing method doesn't send any data. It sets the JCRE to data-send mode. It also accesses and returns the value in the Le byte of the command APDU. As illustrated in APDU Formats, the Le byte indicates the maximum number of bytes expected in response to the command. Notice that the Le byte value for the GET BALANCE command should be 2. The getBalance method checks the Le value; if the value is not 2, the method throws an exception with a constant that is returned in the status word of the response APDU:

// 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
short le = apdu.setOutgoing();

if ( le < 2 )
isoexception.throwit
(iso7816.sw_wrong_length);

getbalance then calls the APDU method setOutgoingLength to specifiy how many bytes of data are actually in the response -- here it's two bytes. The length is specified as a parameter to setOutgoingLength:

//informs the CAD the actual number of bytes

//returned
apdu.setOutgoingLength((byte)2);

Then getBalance moves the balance amount into the first two bytes of the APDU buffer. Notice the shift and bitwise "and" operations performed on the balance value before it is moved into the buffer; these operations correctly produce the values for the two bytes.

// move the balance data into the APDU buffer

// starting at the offset 0
buffer[0] = (byte)(balance >> 8);
buffer[1] = (byte)(balance & 0xFF);

An alternative technique for moving the balance data into the APDU buffer is to use the following method call:

Util.setShort(buffer, (short)0, balance);

setShort is a method defined in the javacard.framework.Util class. It moves a short value (here, the balance) as two successive bytes at the specified offset (offset 0), into a byte array (the APDU buffer).

The last step in the process is to send the data by calling the APDU method sendBytes. The sendBytes method accepts two parameters: the offset into the APDU buffer where the data begins, and the length of the data. Here, the getBalance method sends the two bytes in the APDU buffer starting at offset 0:

// send the 2-byte balance at the offset

// 0 in the apdu buffer
apdu.sendBytes((short)0, (short)2);

} // end of getBalance method

As is the case for the credit and debit methods, the JCRE indicates successful processing of the command APDU by sending a status word value of 0x9000 in the response APDU to the host application.

Validate the PIN

The verify method in the Wallet applet validates the PIN. The method is called with one parameter: an APDU object. The APDU object encapsulates an APDU buffer that contains the VERIFY command APDU. The PIN to be validated is in the data field of the APDU.

private void verify(APDU apdu) {

The verify method first gets a reference to the APDU buffer (for more details, see Get a Reference to the APDU buffer):

byte buffer[] = apdu.getBuffer();

verify then calls the APDU method setIncomingAndReceive to get the PIN to be validated from the command APDU and put it in the APDU buffer:

// retrieve the PIN data for validation.

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

verify then checks the PIN by calling the OwnerPIN method check:

// check pin

// the PIN data is read into the APDU buffer
// at the offset ISO7816.OFFSET_CDATA
// the PIN data length = byteRead
if ( pin.check(buffer, ISO7816.OFFSET_CDATA,
byteRead) == false )
ISOException.throwIt
(SW_VERIFICATION_FAILED);

} // end of validate method
} // end of class Wallet

Notice that the check method is called with three parameters:

  • A byte array that contains the PIN to be validated
  • The offset into the array for the PIN -- the ISO7816 interface constant OFFSET_CDATA is used as the index
  • The length of the PIN

The check method checks the PIN in the APDU buffer against a PIN established when the applet was installed. If the values match, the check method returns a true value. It also sets a flag to indicate that the PIN is validated, and resets a try counter to the maximum value for the applet. Recall that for the Wallet applet the maximum number of tries as set by PIN_TRY_LIMIT is 3. If the values do not match, check returns a false value. In that case, it throws an exception with a constant that is returned in the status word of the response APDU. It also decrements the try counter. If the value of the try counter is 0, check blocks the PIN; this means that no further processing can be performed by the applet for this user.

Java Card Reference

Java Card Classes Used in the Wallet Applet

Class Purpose
APDU Encapsulates the Application Identifier (AID) associated with an applet.
Applet An abstract class that defines an applet in Java Card.
ISOException Encapsulates an ISO7816 status word as its reason code.
OwnerPIN Encapsulates PIN-related data and operations.

Java Card Methods Used in the Wallet Applet

The following Java Card methods are used in the Wallet applet.

javacard.framework.APDU Methods Used in the Wallet Applet

Method Summary
public byte getBuffer()
Returns the APDU buffer byte array.
public void sendBytes(short bOff, short len)
Sends len more bytes from APDU buffer at specified offset bOff.
public short setIncomingAndReceive()
The primary receive method; gets as many bytes as will fit in the APDU buffer without buffer overflow.
public short setOutgoing()
Sets the data transfer direction to outbound and obtains the expected length of the response.
public void setOutgoingLength(short len)
Sets the actual length of the response data.

javacard.framework.Applet Methods Used in the Wallet Applet

Method Summary
public void deselect()
Called by the JCRE to inform the currently selected applet that another (or the same) applet will be selected.
public static void install (byte[] bArray, short bOffset, byte length)
To create an instance of the Applet subclass, the JCRE will call this static method first.
public abstract void process (APDU apdu)
Called by the JCRE to process an incoming APDU command.
protected final void register()
Used by an applet to register this applet instance with the JCRE and to assign an AID to the applet instance.
public boolean select()
Called by the JCRE to inform an applet that it has been selected.

javacard.framework.OwnerPIN Methods Used in the Wallet Applet

Method Summary
public boolean check(byte[] pin, short offset, byte length)
Compares an OwnerPIN object against a PIN.
public boolean getTriesRemaining()
Returns the number of times remaining an incorrect PIN can be presented before the PIN is blocked.
public boolean isValidated()
Returns true if a valid PIN has been since the last card reset or the last call to the reset method; it returns false otherwise.
public boolean reset()
If the validated flag is set, this method resets it. If the validated flag is not set, this method does nothing.
public void update(byte[] pin, short offset, byte length)
Sets a new value for the PIN, resets the PIN try counter to the value of the PIN try limit, and resets the validated flag.

Java Card Interfaces Used in the Wallet Applet

Interface Purpose
ISO7816 Encapsulates ISO7816 constants frequently used in Java Card applets.
PIN Represents a Personal Identification Number (PIN).

APDU Formats

The following is the format of a command APDU. The SELECT APDU command is the only APDU command that is standardized on the Java Card platform. The values in the header of a SELECT APDU command must be as indicated below. The header values for all other command APDU's are applet specific.

Field Length (bytes) Purpose
CLA (class of instruction) 1 Indicates a category of command and response APDUs. Values are:
0x0 ( SELECT)
0xB0 ( CREDIT, VERIFY, DEBIT, GET BALANCE)
INS (Instruction code) 1 Specifies the instruction of the command. Values are:
0xA4 ( SELECT)
0x20 ( VERIFY)
0x30 ( CREDIT)
0x40 ( DEBIT)
0x50 ( GET BALANCE)
P1 (Instruction Parameter 1) 1 Qualifies the instruction. Values are:
0x04 ( SELECT)
0x0 ( VERIFY, CREDIT, DEBIT, GET BALANCE)
P2 (Instruction Parameter 2) 1 Further qualifies the instruction. Values are:
0x0 ( SELECT, VERIFY, CREDIT, DEBIT, GET BALANCE)
Lc 1 Number of bytes present in the data field of the command. Values are:
The length of the AID. For the Wallet applet: 0x08 ( SELECT)
The length of the PIN data ( VERIFY)
1 ( CREDIT, DEBIT)
Not applicable ( GET BALANCE)
Data value of Lc A sequence of bytes in the data field of the command. Values are:
The AID of an applet. For the Wallet applet: 0xF2, 0x34, 0x12, 0x34, 0x56, 0x10, 0x0, 0x1 ( SELECT)
PIN data ( VERIFY)
Credit amount ( CREDIT)
Debit amount ( DEBIT)
Not applicable ( GET BALANCE)
Le 1 Maximum number of bytes expected in the data field of the response to the command. Values are:
Not applicable ( SELECT, VERIFY, CREDIT, DEBIT)
2 ( GET BALANCE)

The following is the format of a response APDU:

Response APDU format

Field Length (bytes) Purpose
Data variable length A sequence of bytes received in the data field of the response. Values are:
Not applicable ( SELECT, VERIFY, CREDIT, DEBIT, GET BALANCE)
SW1 and SW2 (collectively, called the status word) 1 (SW1); 1 (SW2) Denotes the processing state in the card.
0x9000 successful processing ( SELECT, VERIFY, CREDIT, DEBIT, GET BALANCE)
0x6999 applet selection failed ( SELECT)
0x6300 verification failed ( VERIFY)
0x6301 PIN verification required ( CREDIT, DEBIT)
0x6A83 Invalid credit or debit amount ( CREDIT, DEBIT)
0x6A84 Exceeded the maximum amount ( CREDIT)
0x6A85 Negative balance ( DEBIT)

More Information

Java Card 2.1.1 Specifications

Java Card Technology Questions and Answers with Zhiqun Chen

About the Author: Ed Ort is a staff member of the Java Developer Connection. He has written extensively about relational database technology and programming languages.