2017-08-17 19 views
3

コマンドデータが含まれているAPDUを送信しようとしていて、カードからの応答でデータが必要です。私はthis example code by Ludovic Rousseauを始点として使用しています(下記の修正コード)。同じT = 1を使用してデータを送受信する場合APDU

私が送るよ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しか含まれていません。

どのプロトコルがネゴシエートされているかを確認しました。これは、期待通りに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が含まれていますと、すなわち同じAPDUのバイトでdata, sw1, sw2 = connection.transmit(...)を呼び出し、動作します期待されるデータ

これは、カードの関連コードが問題ないと考えています(ただし、完全性のために以下に掲載しています)。

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); 
} 

答えて

3

なぜ私はpyscardで正しいデータを受け取るのか分かりません。しかし、apdu.sendBytesLong()の長さとしてbytesReadを使用することは明らかに間違いである:

  • これはゼロバイトが送信されてしまうのいずれか。これは、コマンドデータのすべてのバイトがAPDUバッファに収まり、既にsetIncomingAndReceive()で検索された場合です。この場合、apdu.receiveBytes(ISO7816.OFFSET_CDATA)は0を返し、はsendBytesLong()を呼び出すとゼロになります。
  • または、送信されるのはわずか数バイトになります。これは、コマンドデータフィールドにAPDUバッファに収まるよりも多くのバイトがある場合です。この場合、bytesReadは、最後の呼び出しで受信されたバイトの数(N)をapdu.receiveBytes(ISO7816.OFFSET_CDATA)に設定します。 sendBytesLong()は、この量(N)のバイトをコマンドデータの先頭から正確に返します。

その結果、カウントはおそらくnumBytes次のようになります。

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

あなたはそれが 'numBytes'(私はそれに応じて変更した)してきたはずですが、それは任意の実際を持っていないことが正しいです私のテストが単一のAPDUバッファに収まるほど十分に小さいように見えるので、この場合の世界的な影響。 – Joost

+1

これで私はその行を見ていましたが、sendBytesLongの代わりに 'sendBytes'を使うためにコードを少し変更しました。その結果、期待される結果が得られますが、明らかに実装のAPDUバッファに収まる小さなデータシーケンスに対してのみ動作します。行動の違いは何ですか?それは 'pyscard'がなぜ機能するのかを説明できますか? – Joost

+2

私は何とか私のテストを台無しにしていて、あなたの修正は本当に変化する必要がある唯一のものです。問題に投稿された状態に戻ってきたので、期待通りに機能します。ありがとう! – Joost

関連する問題