首页 文章

使用相同的T = 1 APDU发送和接收数据

提问于
浏览
3

我'm trying to send an APDU that contains some command data, and then expect some data in response from the card. I' m使用this example code by Ludovic Rousseau作为开始点(下面修改过的代码) .

我发送的APDU如下:

0x80 0x02 0x00 0x00 0x08   0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08   0x08

即我选择了CLA 0x80 ,INS 0x02 ,不使用P1和P2,Lc和Le都是 0x08 .

我回来的数据缓冲区只包含 0x90 0x00 .

我've checked which protocol gets negotiated - that' s T = 1,正如预期的那样 . 如果它是T = 0,我希望得到 61XX -系列答案(见this related question) .

每个其他APDU格式都可以正常工作(即空,只发送或仅接收数据) . 有什么东西我在这里俯瞰吗?

// source: https://ludovicrousseau.blogspot.nl/2010/04/pcsc-sample-in-c.html
// This is based on code by Ludovic Rousseau, modified to match our example

#ifdef WIN32
#undef UNICODE
#endif

#include <stdio.h>
#include <stdlib.h>

#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif

#ifdef WIN32
static char *pcsc_stringify_error(LONG rv)
{
 static char out[20];
 sprintf_s(out, sizeof(out), "0x%08X", rv);

 return out;
}
#endif

#define CHECK(f, rv) \
 if (SCARD_S_SUCCESS != rv) \
 { \
  printf(f ": %s\n", pcsc_stringify_error(rv)); \
  return -1; \
 }

int main(void)
{
 LONG rv;

 SCARDCONTEXT hContext;
 LPTSTR mszReaders;
 SCARDHANDLE hCard;
 DWORD dwReaders, dwActiveProtocol, dwRecvLength;

 SCARD_IO_REQUEST pioSendPci;
 BYTE pbRecvBuffer[258];
 BYTE selectapdu[] = { 0x00, 0xA4, 0x04, 0x00, 0x0A,
                       0x01, 0x02, 0x03, 0x04, 0x05,
                       0x48, 0x45, 0x4C, 0x4C, 0x4F };
 BYTE echoapdu[] = { 0x80, 0x02, 0x00, 0x00, 0x08,
                      0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
                      0x08 };

 unsigned int i;

 rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
 CHECK("SCardEstablishContext", rv)

#ifdef SCARD_AUTOALLOCATE
 dwReaders = SCARD_AUTOALLOCATE;

 rv = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders);
 CHECK("SCardListReaders", rv)
#else
 rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
 CHECK("SCardListReaders", rv)

 mszReaders = calloc(dwReaders, sizeof(char));
 rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
 CHECK("SCardListReaders", rv)
#endif
 printf("reader name: %s\n", mszReaders);

 rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED,
  SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
 CHECK("SCardConnect", rv)

 switch(dwActiveProtocol)
 {
  case SCARD_PROTOCOL_T0:
  printf("T0\n");
   pioSendPci = *SCARD_PCI_T0;
   break;

  case SCARD_PROTOCOL_T1:
  printf("T1\n");
   pioSendPci = *SCARD_PCI_T1;
   break;
 }

// selecting the application

 dwRecvLength = sizeof(pbRecvBuffer);
 rv = SCardTransmit(hCard, &pioSendPci, selectapdu, sizeof(selectapdu),
  NULL, pbRecvBuffer, &dwRecvLength);
 CHECK("SCardTransmit", rv)

 printf("response (%d): ", dwRecvLength);
 for(i=0; i<dwRecvLength; i++)
  printf("%02X ", pbRecvBuffer[i]);
 printf("\n");

// sending a non-empty APDU that expects a reply

 dwRecvLength = sizeof(pbRecvBuffer);
 printf("sent (%d): ",  sizeof(echoapdu));
 for(i=0; i<sizeof(echoapdu); i++)
  printf("%02X ", echoapdu[i]);
 printf("\n");
 rv = SCardTransmit(hCard, &pioSendPci, echoapdu, sizeof(echoapdu),
  NULL, pbRecvBuffer, &dwRecvLength);
 CHECK("SCardTransmit", rv)

 printf("response (%d): ", dwRecvLength);
 for(i=0; i<dwRecvLength; i++)
  printf("%02X ", pbRecvBuffer[i]);
 printf("\n");

// disconnecting

 rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
 CHECK("SCardDisconnect", rv)

#ifdef SCARD_AUTOALLOCATE
 rv = SCardFreeMemory(hContext, mszReaders);
 CHECK("SCardFreeMemory", rv)

#else
 free(mszReaders);
#endif

 rv = SCardReleaseContext(hContext);

 CHECK("SCardReleaseContext", rv)

 return 0;
}

这给出了输出:

reader name: OMNIKEY AG CardMan 3121 00 00
T1
response (2): 90 00 
sent (14): 80 02 00 00 08 01 02 03 04 05 06 07 08 08 
response (2): 90 00

当我尝试使用 pyscard 在Python中执行相同的操作时,一切都按预期工作,即调用 data, sw1, sw2 = connection.transmit(...) 与输入相同的APDU字节使 data 包含预期的数据 .

这让我相信卡上的相关代码很好(但为了完整性也在下面发布) .

private void getEcho(APDU apdu) {
    byte[] buffer = apdu.getBuffer();
    short numBytes = (short) (buffer[ISO7816.OFFSET_LC] & 0x00FF);
    short bytesRead = apdu.setIncomingAndReceive();
    short pos = 0;

    while (pos < numBytes) {
        Util.arrayCopyNonAtomic(buffer, ISO7816.OFFSET_CDATA, transientMemory, pos, bytesRead);
        pos += bytesRead;
        bytesRead = apdu.receiveBytes(ISO7816.OFFSET_CDATA);
    }
    apdu.setOutgoing();
    apdu.setOutgoingLength(numBytes);
    apdu.sendBytesLong(transientMemory, (short)0, bytesRead);
}

1 回答

  • 3

    我不确定为什么你会通过pyscard收到正确的数据 . 但是,使用 bytesRead 作为 apdu.sendBytesLong() 中的长度显然是一个错误:

    • 这将导致发送零字节 . 如果命令数据的所有字节都适合APDU缓冲区并且已经通过 setIncomingAndReceive() 检索到,则会出现这种情况 . 在这种情况下, apdu.receiveBytes(ISO7816.OFFSET_CDATA) 将返回零,并且 bytesRead 在调用 sendBytesLong() 时将为零 .

    • 或者它只会导致发送几个字节 . 如果命令数据字段中的字节数多于适合APDU缓冲区的字节数,则会出现这种情况 . 在这种情况下, bytesRead 将被设置为最后一次调用 apdu.receiveBytes(ISO7816.OFFSET_CDATA) 时接收的字节数(N) . sendBytesLong() 将从命令数据的开头准确返回此数量(N)的字节 .

    因此,计数应该是 numBytes

    apdu.sendBytesLong(transientMemory, (short)0, numBytes);
    

相关问题