Processing the APDU command and generating response data
The first four bytes of the APDU header [CLA, INS, P1, P2] define the instruction that the applet must execute. If the command is of type 3 or 4, then during the execution of the instruction, the applet must process the data read into the APDU buffer. If the command is of type 2 or 4, the applet must generate response data to send to the host application. To reduce the amount of memory used, applet developers often store intermediate results or response data in the APDU buffer.
Sending APDU response data
After executing the instructions specified in the APDU command, the applet can send the response data to the host application. Data exchange takes place in half-duplex mode, so before the data transfer begins, the applet must call the setOutgoing method to inform JCRE that it is ready to send a response to the host application.
public short setOutgoing() throws APDUException
The setOutgoing method puts JCRE into data transfer mode in the direction of the host system. Unlike the similar setIncomingAndReceive method, which is designed to receive data, the setOutgoing method does not forward data. It only changes the data transfer mode. After calling the setOutgoing method, all incoming data that is not received is discarded, and the applet can no longer read data from the current APDU command.
The setOutgoing method returns the number of response bytes (Le) expected by the host application from the applet after processing the current APDU command. If the T=0 protocol is used for communication and the command has type 4, it is impossible to determine the actual value of the Le field, therefore the maximum possible value – 255 is taken as the Le value. In other cases, the number of bytes specified in the Le field of the APDU command is sent. However, the applet does not need to know which transport protocol is used for data transmission.
Even if the host application requests a response of Le bytes, the applet may send more or less data. After calling the setOutgoing method, the applet should call the setOutgoingLength method to tell the host application how much data it is going to actually send (not including SW status words):
public void setOutgoingLength(short length) throws APDUException
The length of the response data block is assumed to be 0 by default, so the applet should not call this method if it is not going to send data to the host application. The applet cannot send more than 256 bytes to the host application. In case of such an attempt, the setOutgoingLength method will raise an APDUException exception with the reason code APDUException.BAD_LENGTH.
Then, to actually send the data, the applet calls the sendBytes method:
public void sendBytes(short bOff, short len) throws APDUException
The sendBytes method sends len bytes of data from the APDU buffer, starting from the offset bOff. Thus, before calling this method, the applet must generate the response data in the APDU buffer or copy the data to the buffer.
The setOutgoing, setOutgoingLength, and sendBytes methods must be called in the correct order, otherwise JCRE will throw an APDUException. This example demonstrates the use of the considered methods in applets:
public void process(APDU apdu) {
// receiving and processing the APDU command
// …
// now the applet is ready to send response data.
// first, we will switch JCRE to data sending mode and get
// the expected length of the response in bytes (Le) short le = apdu.setOutgoing();
// then we will inform the host application that the applet will actually
// send 10 bytes
apdu.setOutgoingLength((short)10);
// preparing data to be sent in the APDU buffer, starting from offset 0
// finally, we send the data
to apdu.sendBytes((short)0, (short)10);
}
If the applet is going to transfer more data than the length of the APDU buffer allows, it must cyclically write new portions of data to the buffer and call the sendBytes method until all data is sent.
To reduce overhead, the APDU class provides a convenient setOutgoingAndSend method for sending outgoing data:
public void setOutgoingAndSend (short bOff, short len)
throws APDUException
The setOutgoingAndSend method combines the functions of the setOutgoing, setOutgoingLength and sendBytes methods and performs the following tasks in one call:
· Puts JCRE in data sending mode.
· Sets the length of the response data to the len value.
· Sends response data from the APDU buffer starting from the bOff offset.
The setOutgoingAndSend method is similar to the setIncomingAndReceive method. Both methods in one call set the data transfer mode, and then send or receive data. However, the setOutgoingAndSend method has a limitation: all data to be sent must fit completely in the APDU buffer. In other words, unlike the setIncomingAndReceive method, after calling setOutgoingAndSend, it will not be possible to change the contents of the APDU buffer and send additional data. But for most APDU commands, the length of the response data field is only a few bytes and does not exceed the size of the APDU buffer. Therefore, to send short responses, it is best to use the setOutgoingAndSend method to reduce the overhead associated with transmission.
Sending data from other locations
The sendBytes and setOutgoingAndSend methods are designed to send data from the APDU buffer. This method of sending is convenient if the data is already in the buffer. If the data is in the applet’s local buffer or in a file, the applet must copy it to the APDU buffer. To reduce the overhead of copying data, the applet can use the sendBytesLong method:
public void sendBytesLong(byte[] outData, short bOff, short len)
throws APDUException
The sendBytesLong method sends len bytes of data from the outData byte array, starting from the bOff offset. Similar to the sendBytes method, the sendBytesLong method can be called several times, but before its first call, the setOutgoing and setOutgoingLength methods must be executed.
Sending large response blocks of data
To send large blocks of data, the applet must consistently call the sendBytes or sendBytesLong method. To send multiple portions of data located in different locations, these methods can be called alternately. This example demonstrates sending a large response block of data.
// After processing the APDU Get_Account_Info command, the applet
// should send to the host system the name of the account holder, the account number and
// the expiration date of the credit card.
// In addition, the applet must send a hash value,
// which is formed from the name, account number and
// expiration date of the credit card and serves to verify
// the correctness of the transmitted data.
//
// The applet stores the name of the account holder, account number and
// expiration date in different bytes arrays:
private byte[] name;// 20 bytes
private byte[] account_number; // 9 bytes private byte[] expiration_date; // 4 bytes
// After processing the APDU command, the applet is ready
// to send response data.
// The length of the data being sent in bytes:
// total_bytes = 20 (name) + 9 (account_number) +
// 4 (expiration_date) + 8 (hash value) = 41 bytes
short total_bytes = (short)41;
// Step 1:
// Switching JCRE to data sending mode
short le = apdu.setOutgoing();
// Step 2:
// let the host application know the actual length of the response data in bytes
apdu.setOutgoingLength(total_bytes);
// Step 3:
// send the name
apdu.sendBytesLong(name, (short)0, (short) name.length);
// send the account number
to apdu.sendBytesLong(account_number, (short)0,
(short)account_number.length);
// send the expiration date of the credit card
to apdu.sendBytesLong(expiration_date, (short)0,
(short)expiration_date.length);
// now calculate the hash value in the APDU buffer.
// Let’s assume that the hash value will be placed starting from offset 0
// send the hash value
to apdu.sendBytes((short)0, HASH_VALUE_LENGTH);
// Return
return;
}
The APDU response consists of an optional data field followed by a mandatory 2-byte status word. After executing the process method of the JCRE applet, it generates the corresponding status word. To avoid additional overhead when transmitting data, JCRE sends the last part of the response data along with the status word. Usually, the sendBytes and sendBytesLong methods send data synchronously, so after returning from them, the applet can immediately start updating the APDU buffer. However, the applet should not change the contents of the APDU buffer after the last call of one of these methods. In the last example, JCRE does not send the hash value immediately after the last call to the sendBytes method. If the applet performs any other tasks before returning from the process method, it should not change the contents of the APDU buffer, otherwise the last portion of data may be distorted during transmission.
Returning the State word
Each call to the process method includes a data exchange operation between the host application and the applet – receiving an APDU command and sending an APDU response. In the process method, the applet first reads the received APDU command, then processes it and generates response data to send. The last stage of the exchange operation is the formation of the APDU state word. The status word informs the host application about the results of executing the instructions contained in the received APDU command. These results are divided into three groups.
- In the case of a normal return from the process method, JCRE automatically sends the host application a status word corresponding to the normal execution of the operation (0x9000). For type 2 or 4 commands, JCRE adds a status word to the applet response data.
- If an error occurs at any time during command processing, the applet interrupts and throws an ISOException exception, calling the static method ISOException.throwIt(reason). The applet passes the status word in the reason parameter. If the ISOException exception is not handled by the applet, it is intercepted by JCRE. JCRE extracts the reason code and sends it as a status word in the same way as when sending the 0x9000 status word, which corresponds to the normal completion of the operation. If the command execution is completed, but there are any problems, the applet can also use the status word to send a warning message.
The ISO7816 interface contains the most commonly used status response words defined in the ISO 7816-4 specification. For example, the constant SW_CLA_NOT_SUPPORTED means that the CLA code of the accepted APDU command is not supported by the applet. The constants that are available in the ISO7816 interface correspond to the status words defined in the ISO 7816-4 specification. Their use makes the applet code more readable and makes it easier to change it.
Before the exception occurs, JCRE may be in transfer mode and data may already be sent. To complete the operation, JCRE adds the status word to the data that has already been received from the applet. - If the error occurred at the lower level of the Java Card system, the behavior of JCRE becomes unpredictable. For example, JCRE can throw an exception like APDUException or TransactionException. JCRE may not provide a handler for this type of exception, or it will be impossible to determine the cause code of the intercepted exception. In any such case, JCRE returns the ISO7816.SW_UNKNOWN (0x6F00) status word without specifying the exact cause of the error. In case of a more serious error, JCRE can suspend the operation of the card, block the current applet, or take any necessary actions to ensure the security and integrity of the applet and the card.