Связь с устройством чтения смарт-карт через Android USB-хост
Я пытаюсь отправить команду на смарт-карту. Я использую Gemalto IDBridge CT30 (считыватель PC TWIN) и IDBridge K30, подключенный к устройству Android через USB.
Я пытаюсь отправить команду SELECT APDU через USB:
boolean claim = openedConnection.claimInterface(usbInterface, true);
byte[] data = new byte[]{
(byte) 0x00, (byte) 0xA4, (byte) 0x04, (byte) 0x0C,
(byte) 0x07, (byte) 0xA0, (byte) 0x00, (byte) 0x00,
(byte) 0x01, (byte) 0x18, (byte) 0x45, (byte) 0x4E};
После этого я получаю ответ:
final int dataTransferred = this.openedConnection.bulkTransfer(endPointOut, data, data.length, TIMEOUT_MS);
if(!(dataTransferred == 0 || dataTransferred == data.length)) {
throw new Exception("Error durring sending command [" + dataTransferred + " ; " + data.length + "]"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
final byte[] responseBuffer = new byte[endPointIn.getMaxPacketSize()];
final int dataTransferred = this.openedConnection.bulkTransfer(this.endPointIn, responseBuffer, responseBuffer.length, TIMEOUT_MS);
Console.writeLine("USB Retrieve: " + dataTransferred + " " + responseBuffer.length);
if(dataTransferred >= 0){
return responseBuffer;
}
throw new Exception("Error durring receinving response [" + dataTransferred + "]");
Этот ответ
0x00 0x00 0x00 0x00 0x00 0xA0 0x00 0x41 0x03 0x00
Тем не менее, я должен получить ответ 0x90 0x00
в соответствии с тестовым проектом здесь.
Что я делаю неправильно? Кто-нибудь может мне помочь? Я использую правильный подход? Я не использую классы пакетов по умолчанию javax.smartcardio
, Я использую классы интерфейса USB (например, UsbDevice) напрямую.
2 ответа
Ваше устройство чтения говорит CCID через интерфейс USB. Вы не можете просто отправить APDU (команду смарт-карты) через конечную точку массового распределения и ожидать получения ответного APDU через конечную точку массового ввода. Вместо этого вам нужно реализовать протокол класса устройства CCID (см. Спецификации класса устройства USB). Шаги что-то вроде:
- Отправьте команду PC_to_RDR_IccPowerOn, чтобы активировать карту.
62 00000000 00 00 00 0000 | | | | | | | | | | | | | \ -> Пустое поле данных | | | | | \ -------> Не используется, установлено 0x0000 | | | | \----------> Power select: 0x00 обозначает автоматический выбор | | | \ -------------> Порядковый номер (приращение для каждой команды) | | \----------------> Номер слота (кажется, ноль для вашего устройства) | \-------------------------> Длина поля данных (сначала LSB) \----------------------------> Тип сообщения: 0x62 указывает PC_to_RDR_IccPowerOn
- Получите ATR через RDR_to_PC_DataBlock.
80 18000000 00 00 00 00 00 3BBF11008131FE45455041000000000000000000000000F1 | | | | | | | | | | | | | | | \ -> Поле данных: ATR | | | | | | \-----> параметр уровня | | | | | \ --------> Регистр ошибок (должен быть равен нулю в случае успеха) | | | | \-----------> Регистр статуса (должен быть равен нулю в случае успеха) | | | \--------------> Порядковый номер (соответствует порядковому номеру команды) | | \-----------------> Номер слота (соответствует номеру слота команды) | \--------------------------> Длина поля данных (сначала LSB) \-----------------------------> Тип сообщения: 0x80 обозначает RDR_to_PC_DataBlock
- Отправить команду APDU, завернутую в команду PC_to_RDR_XfrBlock
6F 0C000000 00 01 00 0000 00A4040C07A000000118454E | | | | | | | | | | | | | \-> Поле данных: Команда APDU | | | | | \-------> Параметр уровня (0x0000 для APDU нормальной длины) | | | | \----------> Заблокировать время ожидания | | | \ -------------> Порядковый номер (приращение для каждой команды) | | \----------------> Номер слота (кажется, ноль для вашего устройства) | \-------------------------> Длина поля данных (сначала LSB) \----------------------------> Тип сообщения: 0x6F указывает PC_to_RDR_XfrBlock
- Получите ответ APDU через RDR_to_PC_DataBlock.
80 02000000 00 01 00 00 00 9000 | | | | | | | | | | | | | | | \ -> Поле данных: Ответ APDU | | | | | | \-----> параметр уровня | | | | | \ --------> Регистр ошибок (должен быть равен нулю в случае успеха) | | | | \-----------> Регистр статуса (должен быть равен нулю в случае успеха) | | | \--------------> Порядковый номер (соответствует порядковому номеру команды) | | \-----------------> Номер слота (соответствует номеру слота команды) | \--------------------------> Длина поля данных (сначала LSB) \-----------------------------> Тип сообщения: 0x80 обозначает RDR_to_PC_DataBlock
- Повторите шаги 3 и 4 для каждого обмена APDU (не забудьте увеличить порядковый номер).
Поскольку ATR указывает T=1 в качестве первого протокола, вам может потребоваться обернуть ваш APDU в T=1 TPDU (в зависимости от конфигурации считывателя). I-блок для первого APDU будет выглядеть примерно так:
00 00 0C 00A4040C07A000000118454E 15 | | | | | | | | | \ -> LRC (из-за отсутствия TC в ATR): контрольная сумма XOR для всех остальных байтов | | | \---------------------------> INF: APDU | | \------------------------------> LEN: длина поля INF | \---------------------------------> PCB: переключение между 0x00 и 0x40 для каждого другого I-блока \------------------------------------> NAD: адресация узлов
Итак, ваша команда PC_to_RDR_XfrBlock будет выглядеть так:
6F 10000000 00 01 00 0000 00 00 0C 00A4040C07A000000118454E 15
Затем вы получите либо ответ, завернутый в I-блок или R- или S-блок, указывающий на необходимость специальной обработки / обработки ошибок.
То, что вы отправляете, это команда SELECT с заданным AID, которая легко может привести к результату. Вы четко указываете, однако, что вы не заинтересованы в ответе,
- установка P2 на "0C"
- не обеспечивает LE байт (предполагается, что протокол на основе блоков, безусловно, целесообразно для USB)
Таким образом, можно сделать вывод, что ваша карта не соответствует ISO 7816-4; с другой стороны, ответ не содержит ничего похожего на состояние ошибки SW1/SW2, вы уверены, что в него был сброшен буфер ответа?