Привет, Гиктаймс!

После общей информации, описанной в первой части, сегодня поговорим об APDU в формате, описанном в стандарте ISO7816-4.

APDU (application protocol data unit) — это формат общения карты и терминала. Терминал посылает Command APDU (C-APDU), а карта отвечает с Response APDU (R-APDU).

C-APDU


Формат C-APDU таков:
Header Body
CLA INS P1 P2 [Lc field] [Data field] [Le field]

Каждый элемент заголовка (header) сохранен на одном байте и является обязательным. К заголовку вернемся чуть позже, сейчас поговорим о body команды.

Элементы body следующие:

  • Lc: длина элемента Data в байтах.
  • Data: данные команды.
  • Le: ожидаемая длина данных ответа в байтах, исключая длину Status Word.


Lc и Le, если присутствуют, могут занимать 1 (Short Length) или 3 байта (Extended Length) каждый. При Short Length кодируются значения от 1 до 256. Длина данных на 256 байтов записывается как «00». При Extended Length кодируются значения от 1 до 65536. Первый байт всегда «00» и остальные 2 байта — номер в формате Big Endian. Когда Lc или Le — «00 00 00», то длина данных — 65536 байтов.

В зависимости от присутствия или отсутствия элементы body команды можно разделить на 4 категории:

  • Case 1: Body полностью отсутсвует, то есть команда не содержит в себе никаких данных и не ожидается получение каких либо данных от карты при ответе.
  • Case 2: В body присутствует только Le, то есть команда не содержит в себе никаких данных, но при этом ожидается получение данных от карты.
  • Case 3: В body присутствуют Lc и Data, то есть команда содержит в себе данные, но при этом не ожидается получение данных от карты.
  • Case 4: В body присутствуют все элементы, а значит команда содержит в себе данные и ожидается получение данных от карты.


Примеры команд я покажу позже. Сейчас вернемся к header.

Элемент Значение
CLA Class байт. Содержит метаданные команды (логический канал, Secure Messaging и т.д.).
INS                 Instruction байт. Код инструкции. Это шестнадцатеричное число, старший ниббл которого не может быть 6 или 9. При этом младший ниббл всегда является четным числом.
P1 Первый параметр команды. Если он не нужен, то его значение «00».
P2 Второй параметр команды. Если он не нужен, то его значение также «00».


Так как серия моих статей нацелена на рассмотрение в подробностях Global Platform, то значение CLA я буду описывать в контексте Global Platform.

CLA байт с логическим каналом от 0 до 3
b8 b7 b6 b5 b4 b3 b2 b1 Значение
0 0 0 0 - - - - Команда из стандарта ISO7816-4
1 0 0 0 - - - - Команда из спецификации Global Platform
- 0 0 0 0 0 - - Нет Secure Messaging
- 0 0 0 0 1 - - Secure Messaging по Global Platform
- 0 0 0 1 0 - - Secure Messaging по ISO7816-4 без C-MAC
- 0 0 0 1 1 - - Secure Messaging по ISO7816-4 с C-MAC
- 0 0 0 - - X X Логический канал

CLA байт с логическим каналом от 4 до 19
b8 b7 b6 b5 b4 b3 b2 b1 Значение
0 1 - 0 - - - - Команда из стандарта ISO7816-4
1 1 - 0 - - - - Команда из спецификации Global Platform
- 1 0 0 - - - - Нет Secure Messaging
- 1 1 0 - - - - Secure Messaging по Global Platform или ISO7816-4
- 1 - 0 X X X X Логический канал

b7 определяет, если формат CLA как в первой или как во второй таблице. Когда логический канал находится в промежутке от 0 до 3, то его значение записывается в битах 1 и 2. Иначе, число записанное в битах 1-4 кодирует номер от 4 до 19 (0 = 4, 1 = 5, ..., 15 = 19).

b5 в стандарте ISO7816-4 обозначает Command Chaining. В Global Platform не используется.

R-APDU


Формат R-APDU таков:
Body Trailer
[Data field] SW1 SW2

Body присутствует при успешном исполнении (с замечаниями или без них) команд из категории Case 2 и Case 4. Его содержание зависит от конкретной команды. Trailer есть всегда и содержит так называемый Status Word, то есть код результата, положительного или отрицательного. Статус может быть одним из следующих:

SW1SW2 Значение
Успешное исполнение
9000 ОК.
61ХХ ОК, но есть еще ХХ байтов данных.
Исполнение завершилось с замечаниями
62ХХ SW2 уточняет причины замечания. Постоянная память не была изменена.
63ХХ SW2 уточняет причины замечания. Постоянная память была изменена.
Ошибки при исполнении команды
6400 Команда не была исполнена. Постоянная память не была изменена.
65ХХ Команда не была исполнена. Постоянная была изменена.
66ХХ Команда не была исполнена по причинам безопасности.
Ошибки, связанные с форматом команды
6700 Неправильная длина команды.
6881 Карта не поддерживает указанный логический канал.
6882 Карта не поддерживает указанный вид Secure Messaging.
69XX Команда не разрешена.
6AХХ Неправильные параметры команды.
6B00 Неправильные параметры команды.
6CXX Неправильный Le.
6D00 Неизвестный INS.
6E00 Неизвестный CLA.
6F00 Ошибка без описания.

Ошибки из серии 69ХХ и 6АХХ часто используются в Global Platform и будут описаны в подробностях в частях статьи, посвященных Global Platform.

Статусы из серии 61ХХ и 6CXX требуют особенного внимания. Код 61ХХ возможен, когда карта исполнила команду из категории Case 2 или Case 4 и послала неполный ответ. В этом случае, SW2 кодирует длину остатка ответа («00» = 256). В ответ терминал может отправить команду GET RESPONSE для того, чтобы получить оставшиеся данные. Эта процедура может повторяться несколько раз, до тех пор, пока карта не отправит полный ответ. Настоящий Status Word — это статус, содержащийся в последнем ответе на команду GET RESPONSE. Подобная ситуация встречается преимущественно, когда APDU передается через протокол ISO7816-3 T=0 ввиду особенности передачи команд из категории Case 4 (об этом поговорим чуть позже). Код 6CXX встречается, когда указанный Le не соответствует действительной длине ответа. Стоит отметить, что при этом карта не посылает никаких данных в R-APDU, а требует, чтобы терминал повторил команду с Le равным числу, закодированному в SW2.

Особенности передачи команд в категории Case 4 через протокол Т=0


Протокол T=0 очень распространен, так как он используется в SIMках. Его особенность заключается в том, что header всегда состоит из 5 байтов: CLA, INS, P1, P2, P3. P3 может быть использован для кодировки Lc либо Le. Получается, что он, будет лишним для команд Case 1, подходит для команд Case 2 и Case 3, но недостаточен для команд Case 4, где нужны как Lc, так и Le. Как можно решить эту проблему?

Следующим образом. Команды Case 4 передаются с P3=Lc, как будто это команда Case 3. Тогда карта, при успешном исполнении команды, отвечает без данных, но со статусом 61ХХ. В свою очередь терминал посылает команду GET RESPONSE (из категории Case 2), а затем карта посылает настоящий ответ.

GET RESPONSE
Элемент Значение
CLA как предыдущая команда, но без Secure Messaging и бит8 = 0 (хотя карты принимают и бит8 = 1)
INS C0
P1 00
P2 00
Lc -
Data -
Le XX (обычно SW2 предыдущего ответа)


Примеры общения с картой


Наконец-то, мы подошли к самой интересной части статьи — примеры.

GET DATA (Card Production Life Cycle)
C-APDU => 80 CA 9F 7F 00
R-APDU <= 6C 2D
C-APDU => 80 CA 9F 7F 2D
R-APDU <= 9F 7F 2A 47 90 50 40 47 91 81 02 31 00 83 58 00 11 68 91 45 81 48 12 83 65 00 00 00 00 01 2F 31 30 31 31 36 38 00 00 00 00 00 00 00 00 90 00

Команда GET DATA (Case 2) читает информацию с карты. Какую именно — определяется параметрами P1 и P2. Ответ в формате BER-TLV (субъект следующей части статьи). Здесь мы видим как в начале команда была отправлена с неправильным Le и карта, в свою очередь, ответила со статусом 6C 2D. После повтора команды с Le = 2D, карта отправила ответ и конечный статус 9000, обозначающий успешное исполнение.

GET STATUS через Т=1
C-APDU => 80 F2 40 00 08 4F 06 31 32 33 34 35 36 09
R-APDU <= 06 31 32 33 34 35 36 07 00 90 00

Команда GET STATUS (Case 4) дает информацию о жизненном цикле карты и приложений. В данном примере Lc = 8, Data = 4F 06 31 32 33 34 35 36 и Le = 9. На данном этапе не буду углубляться в объяснение значения этих данных, поскольку это не так важно. Карта в ответ посылает данные 06 31 32 33 34 35 36 07 00 и статус 9000. Ниже посмотрим точно такую же команду, только отправленную через протокол Т=0.

GET STATUS через Т=0
C-APDU => 80 F2 40 00 08 4F 06 31 32 33 34 35 36
R-APDU => 61 09
C-APDU => 00 C0 00 00 09
R-APDU <= 06 31 32 33 34 35 36 07 00 90 00

Здесь мы видим, что GET STATUS отправляется без Le. Протокол не позволяет нам этого, поскольку в P3 указан Lc. В ответ карта скажет нам длину данных, которые мы должны получить. Затем мы отправляем команду GET RESPONSE с Le = 9. После этого карта, наконец, посылает нам соответствующий ответ.

Итак мы подошли к концу этой части. Если у кого-то будут вопросы, вы можете написать их в комментариях. Следующая часть статьи будет о BER-TLV, так как этот формат кодирования данных используется практически для всего, что связано со смарт-картами.

Остальные части статьи


Часть 1. Принципы работы
Часть 3. TLV

Комментарии (0)