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:
| 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
Technology for Smart Cards: Architecture and Programmer's Guide
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.
Back To Top
|