An Application Protocol Data Unit (APDU) is simply a byte array that contains information following the ISO 7816 standard. There are two kinds of APDU:
The application running on the host machine (in PIV, that is "Off-Card") sends a Command APDU, and the YubiKey returns a response APDU.
Here is an example of a command APDU, and its and response.
command APDU: 00 87 03 9B 04 7C 02 80 00 response APDU: 7C 0A 80 08 3D 12 D6 71 F7 32 75 0D 90 00
There are up to seven elements in a command APDU. All command APDUs must have the first four, but it is legal to have the first four, five, six, or seven elements.
Table 1.1: Possible command APDU elements
|Class||Instruction||Param 1||Param 2||Length of Data||Data||Max Length of Response Data|
For example, with the command APDU
00 87 03 9B 04 7C 02 80 00, these are the elements.
Table 1.2: Example command APDU elements
|00||87||03||9B||04||7C 02 80 00||(absent)|
When building command APDUs in the SDK, the
Le value will always be absent. The
value is the maximum number of bytes in the data response. However, we will not specify
that. Rather, we will let the YubiKey return as many bytes as it will, and check the
length in each command class.
For example, when getting the version, we expect the return data to contain three bytes.
We could set
Le to 3. If so, then the class that actually sends the APDU (a
Connection class) could check the length of the return data for an appropriate
length. It could throw an exception or return an error.
However, we will instead make that check in the class that processes the specific command. In that way, if there is an error, the exception or error return can be generated by the class that knows what the command really is and create a more specific error message.
A response APDU consists of up to three elements.
Table 2.1: Possible response APDU elements
|Data||Status Word 1||Status Word 2|
The last two bytes make up the status word, which is the error or success code. A response might contain data and the status word, or just the status word.
For example, with the response APDU
7C 0A 80 08 3D 12 D6 71 F7 32 75 0D 90 00, these
are the elements.
Table 2.2: Example response APDU elements
|7C 0A 80 08 3D 12 D6 71 F7 32 75 0D||90||00|
Note that if there is an error, the response APDU will be two bytes only: SW1 and SW2.
For example, the two-byte response of
6A 81 means "Card is blocked or command not
Table 2.3: Response APDU indicating error
It is also possible to have a successful response APDU of only two bytes (no data). For
example, suppose a command APDU requests the YubiKey set the number of PIN retries to
five (instead of the default three). If the YubiKey successfully sets the retry count,
there is no data to be returned, simply the status word,
90 00, indicating success.
Table 2.4: Response APDU indicating success with no data
There is a limit to the length of an APDU. For a command APDU, the limit is 260, and for a response APDU it is 258. If the amount of data to send would cause the APDU to exceed the limit, then it must be sent in more the one call.
Command APDU chaining
For a command APDU, chaining generally means setting the CLA to
10 | CLA (OR 0x10 with
the CLA) for the APDUs which do not contain all the data. That is, use the normal CLA
value, but just set the
0x10 bit. This indicates that there will be one or more
command APDUs following, each with more data. Each of the following command APDUs will
be the same as the first, just with more data. Then, for the last APDU (it holds the
last of the data), set the CLA to be the regular value (no
For example, suppose you were sending the PIV command "Sign" for a 2048-bit RSA key. Here's what the command APDU would be.
|00||87||07||9c||data len||7c L1 82 L2 81 L3 <encoded data to sign>||absent|
The Data is made up of these elements.
|tag (auth template)||length (DER)||tag (response)||length (DER)||tag (challenge)||length (DER)||PKCS 1 v1.5 or PSS|
The actual data we will send will be the following.
|decimal 262||00 (this is not a response)||decimal 256||PKCS 1 v1.5|
|7c||82 01 06||82||00||81||82 01 00||00 01 FF FF ... FF 00 <DigestInfo>|
There will be 268 bytes of data to send. The APDU's field Lc is one byte only, so the maximum value it can represent is 255. So break the data into two commands.
First command APDU
|10||87||07||9c||d6||7c 82 01 06 82 00 81 82 01 00 00 01 ff ff ... ff||absent|
|0x10 set, more data in following APDU||Lc is 214, number of bytes in APDU's data||214 bytes|
Second command APDU
|00||87||07||9c||34||ff ff ff 00 30 2f ... 1F||absent|
|0x10 NOT set, last of the data in this APDU||Lc is 52, number of bytes in APDU's data||52 bytes, the rest of the data|
For both calls, the CLA, INS, P1, and P2 values are the same (except for the
in the CLA of the first call). The data is simply broken up.
Notice that the data in the first APDU contains some TLV constructions. But those tags are not in the second APDU's data. The second APDU simply continues with the data.
Response APDU chaining
If the YubiKey needs to return more than 256 bytes of data, it will need to break it up into multiple response APDUs.
The response APDU will contain up to 256 bytes of data, followed by SW1 and SW2. If SW1
61, then SW2 contains the number of bytes that still need to be returned.
The application running on the host (off-card) will receive the data, and when getting to
the status word, will see that there are more bytes waiting to be transferred. At that
point, the application needs to send a new command APDU: GET RESPONSE (
00 c0 00 00).
For example, suppose the application wanted a copy of the attestation certificate. The process would look something like this.
command APDU: 00 cb 3f ff 05 5c 03 5f ff 01 response APDU: 53 82 02 f5 ... 61 ff command APDU: 00 c0 00 00 response APDU: a9 e9 c1 5b ... 61 f9 command APDU: 00 c0 00 00 response APDU: 28 42 e5 8d ... 90 00
The first command APDU is GET DATA and the data it is requesting is the attestation cert.
The first response APDU starts sending the cert. SW1 is
61, meaning there's more data,
and SW2 is
ff meaning there is at least 255 bytes of data still to transfer.
So the application sends the GET RESPONSE APDU. The YubiKey returns more data (simply
picking up where it left off), and SW1 of
61 (more data still) and SW2 of
249 bytes left).
The application sends GET RESPONSE again. This time the response is 249 bytes of data and SW1, SW2 of 90 00, meaning success, so there's no more data.