PC/SC: "Карта не транзакция" при использовании вызовов C-API

Несколько недель назад я начал экспериментировать со смарт-картами для университетского проекта. Упражнение было таким же простым, как использование карточки медицинского страхования (немецкая "eGK"), выяснение того, что на ней сохранено, и считывание "общедоступных" частей, которые можно прочитать без какой-либо проверки подлинности.

К счастью, структура карты хорошо задокументирована, и документацию можно легко загрузить из Интернета. То, что я в основном хочу сейчас, это выбрать EF (MF / DF.HCA / EF.VD) и зачитать данные. Файл, который я хочу прочитать, является двоичным файлом. Согласно документации, первые 2x4 байта представляют начальные / конечные смещения двух частей файла. Каждая часть должна быть сжатой gzip XML.

Сначала я использовал "scriptor" из инструментов pcsc-lite, чтобы опробовать несколько команд, посмотреть, работает ли он, и могу ли я получить некоторые разумные результаты. Все получилось довольно хорошо:)

$ scriptor
No reader given: using Towitoko Chipdrive USB 00 00
Using T=1 protocol
Reading commands from STDIN
reset
> RESET
< OK: 3B DD 97 FF 81 B1 FE 45 1F 03 00 64 04 05 08 03 73 96 21 D0 00 90 00 C8 
00 a4 04 0c 06 d2 76 00 00 01 02    # Select DF
> 00 a4 04 0c 06 d2 76 00 00 01 02
< 90 00 : Normal processing.
00 a4 02 0c 02 d0 02                # Select EF
> 00 a4 02 0c 02 d0 02
< 90 00 : Normal processing.
00 b0 00 00 08                      # Read out start/end offsets
> 00 b0 00 00 08
< 00 08 01 AD 01 AE 02 7C 90 00 : Normal processing.

Как вы можете видеть, это будет более 400 байтов для считывания (и распаковки их впоследствии), поэтому я решил, что мне нужно написать какую-нибудь программу, которая считывает это для меня. С помощью этого поста в блоге: http://ludovicrousseau.blogspot.de/2010/04/pcsc-sample-in-c.html я быстро смог отправить свои первые команды на карту, используя C. Основной поток моих Программа это:

  1. Установить контекст
  2. Получить ридер (программа распечатывает ридер в использовании, и он единственный и правильный;))
  3. Получить карту (протокол T=1)
  4. Сбросить карту
  5. Скажите PC/SC мне нужна транзакция
  6. Передай команды
  7. Конец транзакции

Вот поля, которые я отправляю в СЦ:

//                    CLA   INS    P1     P2            LEN_SEND
BYTE cmdSelectDF[] = {0x00, 0xA4,  0x04,  0x0C,         0x06,
//                    00    SELECT DF/AID first/noanswer
//                    <- HEADER] ----- [DATA ->
//                    D6    D5    D4     D3    D2    D1
                      0xD2, 0x76, 0x00,  0x00, 0x01, 0x02};

//                    CLA   INS    P1     P2            LEN_SEND
BYTE cmdSelectEF[] = {0x00, 0xA4,  0x02,  0x0C,         0x02,
//                    00    SELECT EF/FID first/noanswer
//                    <- HEADER] ----- [DATA ->
//                    D2    D1
                      0xD0, 0x02};

//                       CLA   INS         P1      P2      LEN_RECV
BYTE cmdReadOffsets[] = {0x00, 0xB0,       0x00,   0x00,   0x08};
//                       00    READ BINARY OFFSET1 OFFSET2 BYTES

Первые две команды передаются просто отлично, и я всегда получаю 0x90 0x00 обратно. К сожалению, ReadOffsets-Transmit возвращается с ошибкой: "транзакция не удалась". В журнале говорится следующее:

00000011 winscard.c:1613:SCardTransmit() Send Protocol: T=1
00042572 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000030 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x0 for client 6
03000349 winscard_svc.c:356:ContextThread() Received command: TRANSMIT from client 6
00000043 readerfactory.c:798:RFReaderInfoById() RefReader() count was: 1
00000012 winscard.c:1613:SCardTransmit() Send Protocol: T=1
00055517 ifdwrapper.c:553:IFDTransmit() Card not transacted: 612
00000027 winscard.c:1638:SCardTransmit() Card not transacted: 0x80100016
00000010 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000031 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x80100016 for client 6
00000297 winscard_svc.c:348:ContextThread() Client die: 6
00000029 winscard.c:230:SCardReleaseContext() Releasing Context: 0x420027B7

У кого-нибудь есть идея, что это значит и почему это происходит? Что я делаю неправильно?

Заранее большое спасибо!

Изменить: у меня есть новости для вас. Я нашел некоторые #ifdefs в исходном коде драйвера towitoko для целей отладки. Теперь у меня есть гораздо более подробный файл журнала для вас. Детали с [[[]]] находятся только в файле журнала ошибок. Как видите, нет никакой разницы в отправленных байтах и ​​полученных байтах вообще!

01942065 winscard_svc.c:356:ContextThread() Received command: TRANSMIT from client 6
00000021 readerfactory.c:798:RFReaderInfoById() RefReader() count was: 1
00000008 winscard.c:1613:SCardTransmit() Send Protocol: T=1
IFD: Setting baudrate to 9600
IFD: Transmit: 0 40 7 0 A4 2 C 2 D0 2 3D 
IO: Sending: 6F B 5 5A 
IO: Sending: 0 
IO: Sending: 40 7 0 A4 2 C 2 D0 2 3D 
IO: Receiving: 0 
IO: Receiving: 40 2 90 
IFD: Receive: 0 40 2 90 
IO: Receiving: 0 D2 
IFD: Receive: 0 D2 
00042861 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000011 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x0 for client 6
IO: Sending: 3 7 
IO: Receiving: 42 87 
IFD: Status = card / no change
IO: Sending: 3 7 
IO: Receiving: 40 83 
IFD: Status = card / no change
[...]
02773187 winscard_svc.c:356:ContextThread() Received command: TRANSMIT from client 6
00000032 readerfactory.c:798:RFReaderInfoById() RefReader() count was: 1
00000009 winscard.c:1613:SCardTransmit() Send Protocol: T=1
IFD: Setting baudrate to 9600
IFD: Transmit: 0 0 5 0 B0 0 0 8 BD 
IO: Sending: 6F 9 5 52 
IO: Sending: 0 
IO: Sending: 0 5 0 B0 0 0 8 BD 
IO: Receiving: 0 
IO: Receiving: 0 A 0 
IFD: Receive: 0 0 A 0 
IO: Receiving: 8 1 AD 1 AE 2 7C 90 0 EF 
IFD: Receive: 8 1 AD 1 AE 2 7C 90 0 EF 
[[[ 00054674 ifdwrapper.c:553:IFDTransmit() Card not transacted: 612
00000011 winscard.c:1638:SCardTransmit() Card not transacted: 0x80100016 ]]]
00054759 winscard.c:1658:SCardTransmit() UnrefReader() count was: 2
00000011 winscard_svc.c:656:ContextThread() TRANSMIT rv=0x0 for client 6

Итак, откуда это сообщение об ошибке?

Еще одна вещь, которую я узнал, заключается в том, что эта ошибка не является специфической для читателя. Я пробовал программу на внутреннем устройстве чтения карт друга (Windows говорит, что это устройство Broadcom), которое дает те же результаты. Поскольку единственный случай, о котором я могу подумать, это ошибка в моей C-программе, вот исходный код с базовыми макросами и частью соединения:

// Parts taken from http://ludovicrousseau.blogspot.de/2010/04/pcsc-sample-in-c.html
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <PCSC/pcsclite.h>
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>

#define EGK_RECV_BUFSIZE 258

#define PCSC_ERROR(debugmsg, retval) \
    if(retval != SCARD_S_SUCCESS) { \
        fprintf(stderr, "PC/SC Error at %s: %s\n", debugmsg, pcsc_stringify_error(retval)); \
        return 1; \
    }

#define TRANS_RESPONSE \
    printf("Command response: "); \
    for(i = 0; i < dwRecvLen; i++) { \
        printf("%02X ", recvBuffer[i]); \
    } printf("\n");

#define CHECK_SUCCESS \
    if(dwRecvLen >= 2) { \
        if(recvBuffer[dwRecvLen-2] == 0x90 && recvBuffer[dwRecvLen-1] == 0x00) { \
            printf("Command success!\n"); \
        } \
    }

#define SCARD_TRANSMIT(cmd) \
    SCardTransmit(scHandle, &scSendProto, cmd, sizeof(cmd), NULL, recvBuffer, &dwRecvLen);

int main(void)
{
    LONG retval = 0;                            // = long
    SCARDCONTEXT scContext;                     // = LONG
    LPTSTR scReaders;                           // = LPSTR = char *
    SCARDHANDLE scHandle;                       // = LONG (specific smartcard)
    DWORD dwReaders, dwCurProto, dwRecvLen;     // = unsigned long

    SCARD_IO_REQUEST scSendProto;
    BYTE recvBuffer[EGK_RECV_BUFSIZE];

    // BYTE cmdXXX[] = {...}; ... SEE ABOVE!

    // Get Context
    retval = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &scContext);
    PCSC_ERROR("1 Establish Context", retval);

    // Get Reader

    retval = SCardListReaders(scContext, NULL, NULL, &dwReaders);
    PCSC_ERROR("2.1 Get Readers", retval);

    scReaders = calloc(dwReaders, sizeof(DWORD));

    retval = SCardListReaders(scContext, NULL, scReaders, &dwReaders);
    PCSC_ERROR("2.2 Get Readers", retval);

    printf("Reader name: %s\n", scReaders);

    // Get Card

    retval = SCardConnect(scContext, scReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &scHandle, &dwCurProto);
    PCSC_ERROR("3 SCardConnect", retval);

    // Reset
    retval = SCardReconnect(scHandle, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &dwCurProto);
    PCSC_ERROR("4 RESET Card", retval);

    dwRecvLen = EGK_RECV_BUFSIZE;

    if(dwCurProto == SCARD_PROTOCOL_T0) {
        scSendProto = *SCARD_PCI_T0;
    } else if(dwCurProto == SCARD_PROTOCOL_T1) {
        scSendProto = *SCARD_PCI_T1;
    } else {
        fprintf(stderr, "No known protocol selected\n");
        return 1;
    }

Передающая часть выглядит одинаково для каждой команды. Пример:

printf("READ BINARY -> First 8 Bytes (Offsets)\n");
retval = SCARD_TRANSMIT(cmdReadOffsets);
PCSC_ERROR("8 Transmit READ BINARY", retval);

TRANS_RESPONSE;
CHECK_SUCCESS; printf("\n");

Изменить: Извините, это редактирование приходит так поздно, я полностью забыл об этом посте! В конце концов мне удалось заставить его работать, переписав мою программу на Java. Я знаю, что это не совсем удовлетворительный ответ для тех, кто может наткнуться на этот вопрос. По крайней мере, теперь мы можем быть уверены, что ошибка лежит где-то внутри кода C. Если кто-нибудь знает, почему программа не работает, в любом случае, не стесняйтесь отвечать, мне было бы очень интересно узнать, какую ошибку я допустил:)!

0 ответов

Другие вопросы по тегам