【问题标题】:WinSCard SCARD_E_PROTO_MISMATCH when connecting to Estonian ID cardWinSCard SCARD_E_PROTO_MISMATCH 连接到爱沙尼亚身份证时
【发布时间】:2016-09-28 21:50:24
【问题描述】:

我正在尝试读取爱沙尼亚身份证的个人文件。

我需要将以下数据发送到卡(从 here) 以便从个人档案中读取记录(即身份证号、姓名等):

00 A4 00 0C          # We choose root folder
00 A4 01 0C 02 EE EE # We choose folder EEEE
00 A4 02 04 02 50 44 # We choose file 5044, which contains personal data
00 B2 XX 04          # We read record XX (see table) from the personal data file
                     # The card responds 61 YY, where YY denotes the number of bytes waiting to be read
00 C0 00 00 YY       # We read YY bytes from the card
                     # Card responds ... 90 00, where ... is the requested data and 90 00 means status OK 

但是,原始字节在 T=0 协议中,并且卡在接受 T=0 之前卡在 T=1 中的时间过长。事件顺序如下:

  1. 卡已连接到读卡器
  2. 程序从SCardStatusChange返回并开始处理卡片
  3. 在尝试连接到卡(SCardConnectSCardReconnect)时,反复收到错误 SCARD_E_SHARING_VIOLATION,持续大约 5 秒
  4. 然后,在尝试连接时,会在 3 到 30 秒之间的任何时间收到错误 SCARD_E_PROTO_MISMATCH,可能更长。
  5. 之后,卡连接成功并读取数据。

我能否以某种方式在 T=0 协议中更快地连接到它?

我的源代码简化版如下:

// NOTE: this is approximately what I do.
// I haven't tested this code yet - it's almost 1 AM here.
#include <winscard.h>
void readSmartCard() {
    LONG sCardErrorCode;
    SCARDCONTEXT sCardContext;
    DWORD sCardReaderStrLen = 1024;
    wchar_t sCardReaderStr[1024];
    SCARDHANDLE sCardHandle;
    DWORD sCardActiveProtocol;
    SCARD_READERSTATE readerState;

    sCardErrorCode = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &sCardContext);

    // error handling macro

    ZeroMemory(&sCardReaderState, sizeof(sCardReaderState));
    sCardReaderState.szReader = L"\\\\?PnP?\\Notification";
    sCardReaderState.pvUserData = nullptr;
    sCardReaderState.dwEventState = SCARD_STATE_PRESENT;

    sCardErrorCode = SCardGetStatusChange(sCardContext, INFINITE, &readerState, 1);

    // e.h.m

    if (readerState.dwCurrentState == 65538) {
        sCardErrorCode = SCardListReaders(sCardContext, NULL, sCardReaderStr, &sCardReaderStrLen);
        // e.h.m
        readerState.szReader = sCardReaderStr;
    }

    sCardErrorCode = SCardGetStatusChange(sCardContext, INFINITE, &readerState, 1);
    // e.h.m

    if (sCardReaderState.dwEventState & SCARD_STATE_PRESENT) {

        while (true) {
            sCardErrorCode = SCardConnect(sCardContext, readerState.szReader, SCARD_SHARE_EXCLUSIVE,
                SCARD_PROTOCOL_T0, &sCardHandle, &sCardActiveProtocol);

            // e.h.m
            printf("%x", sCardErrorCode); 
            // this will print:
            // 8010000b (for around 5s)
            // 8010000f (for around 20s)
            if (sCardErrorCode == SCARD_S_SUCCESS) {
                break;
            }
            Sleep(1000);
        }

        // open personal file and read data, yay!
    }
}

【问题讨论】:

  • 1) 对于进行连接,使用的协议不应在性能上产生显着差异。 2) 支持 T=0 和 T=1 的卡已经足够不寻常了 3) 如有疑问,请始终使用 T=1,这对于应用程序来说更容易,并且在安全消息传递方面更健壮。

标签: c++ winapi smartcard winscard id-card


【解决方案1】:

在网上搜索了很长时间后,我发现不需要更改命令。

我只需要在传输的读取/打开命令的末尾添加一个额外的零字节,并接收数据作为读取命令的响应,而不是使用单独的命令来接收字节。 (T=0 使用“请求数据/读取数据”模型,而 T=1 似乎只是响应数据)

我还需要更改所有提及 SCARD_PCI_T0 以有条件地使用 SCARD_PCI_T1 并使 SCardConnect() 函数也接受 T1。

稍后我会在这里发布一个不错的代码示例。

【讨论】:

    【解决方案2】:

    您要求SCardConnect() 仅对T0 协议进行独占访问,因此如果卡正在使用,则返回SCARD_E_SHARING_VIOLATION,如果卡未使用但T1 处于活动状态,则@而是返回 987654326@。

    SCardGetStatusChange() 报告通知时,您只检查SCARD_STATE_PRESENT 标志,但也可以存在您忽略的其他标志,例如SCARD_STATE_INUSE

    如果您需要阅读器的独占访问权限,则必须等到SCARD_STATE_INUSE 被清除,和/或SCARD_E_SHARING_VIOLATION 不再开始报告。对此您无能为力,除非您更改逻辑以允许以共享模式而不是独占模式进行连接。

    如果您想连接到阅读器而不考虑其当前协议(从而更快地获得独占访问权限),您可以要求SCardConnect() 接受两个 T0T1 协议同时,通过在dwPreferredProtocol 参数中将它们组合在一起(参见documentation 中的示例)。然后,如果pdwActiveProtocol 参数输出T1 是活动协议,您可以等待状态更改为T0 协议,然后再读取卡。

    【讨论】:

    • 感谢您的回复。我会改进已经拿卡的情况。但是,我不知道如何在 T=1 中执行我需要的操作(导航到文件夹、打开个人数据文件、读取记录),这使我无法支持该协议。如果我不能在 T=0 更快地打开卡,我会研究 T=1 看看我是否也可以在那里做我需要的事情。 (在这种情况下,独占访问也可能没用,但我试图赶上最后期限,所以我想避免任何与共享有关的问题)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-18
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    • 1970-01-01
    • 2020-11-28
    • 2019-06-22
    相关资源
    最近更新 更多