WinSCard SCARD_E_PROTO_MISMATCH 连接到爱沙尼亚身份证时
WinSCard SCARD_E_PROTO_MISMATCH when connecting to Estonian ID card
我正在尝试读取爱沙尼亚身份证的个人档案。
我需要向卡发送以下数据(来自
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 停留了不合理的长时间。事件顺序如下:
- 卡已附加到 reader
- 从
SCardStatusChange
编程 returns 并开始处理卡
- 在尝试连接到卡(
SCardConnect
或 SCardReconnect
)时,一遍又一遍地收到错误 SCARD_E_SHARING_VIOLATION
,大约持续 5 秒
- 然后,在尝试连接时,在 3 到 30 秒之间的任何时间收到错误
SCARD_E_PROTO_MISMATCH
,可能更长时间。
- 之后卡连接成功,读取数据
我能以某种方式在 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!
}
}
您要求 SCardConnect()
仅对 T0
协议进行独占访问,因此如果卡在使用中,则返回 SCARD_E_SHARING_VIOLATION
,如果卡未在使用中,则返回 SCARD_E_SHARING_VIOLATION
但是 T1
处于活动状态,然后返回 SCARD_E_PROTO_MISMATCH
。
当 SCardGetStatusChange()
报告通知时,您只检查 SCARD_STATE_PRESENT
标志,但也可能存在您忽略的其他标志,例如 SCARD_STATE_INUSE
。
如果您需要独占访问reader,您将不得不等到SCARD_STATE_INUSE
被清除,and/or SCARD_E_SHARING_VIOLATION
不再开始报告。你对此无能为力,除非你改变你的逻辑以允许在共享模式而不是独占模式下连接。
如果你想连接到 reader 而不管它的当前协议(从而更快地获得独占访问权),你可以要求 SCardConnect()
接受 both T0
和 T1
协议,通过在 dwPreferredProtocol
参数中将它们组合在一起(参见 documentation 中的示例)。然后,如果 pdwActiveProtocol
参数输出 T1
是活动协议,您可以在读卡之前等待 T0
协议的状态更改。
在互联网上搜索了很长时间后,我发现不需要对命令进行任何更改。
我只需要在传输的 read/open 命令末尾添加一个额外的零字节,并接收数据作为读取命令的响应,而不是使用单独的命令来接收字节。 (T=0 使用了 "request data/read data" 模型,而 T=1 似乎只是用数据响应)
我还需要更改所有提及的 SCARD_PCI_T0
以有条件地使用 SCARD_PCI_T1
并使 SCardConnect()
函数也接受 T1。
稍后我会post在这里提供一个不错的代码示例。
我正在尝试读取爱沙尼亚身份证的个人档案。
我需要向卡发送以下数据(来自 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 停留了不合理的长时间。事件顺序如下:
- 卡已附加到 reader
- 从
SCardStatusChange
编程 returns 并开始处理卡 - 在尝试连接到卡(
SCardConnect
或SCardReconnect
)时,一遍又一遍地收到错误SCARD_E_SHARING_VIOLATION
,大约持续 5 秒 - 然后,在尝试连接时,在 3 到 30 秒之间的任何时间收到错误
SCARD_E_PROTO_MISMATCH
,可能更长时间。 - 之后卡连接成功,读取数据
我能以某种方式在 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!
}
}
您要求 SCardConnect()
仅对 T0
协议进行独占访问,因此如果卡在使用中,则返回 SCARD_E_SHARING_VIOLATION
,如果卡未在使用中,则返回 SCARD_E_SHARING_VIOLATION
但是 T1
处于活动状态,然后返回 SCARD_E_PROTO_MISMATCH
。
当 SCardGetStatusChange()
报告通知时,您只检查 SCARD_STATE_PRESENT
标志,但也可能存在您忽略的其他标志,例如 SCARD_STATE_INUSE
。
如果您需要独占访问reader,您将不得不等到SCARD_STATE_INUSE
被清除,and/or SCARD_E_SHARING_VIOLATION
不再开始报告。你对此无能为力,除非你改变你的逻辑以允许在共享模式而不是独占模式下连接。
如果你想连接到 reader 而不管它的当前协议(从而更快地获得独占访问权),你可以要求 SCardConnect()
接受 both T0
和 T1
协议,通过在 dwPreferredProtocol
参数中将它们组合在一起(参见 documentation 中的示例)。然后,如果 pdwActiveProtocol
参数输出 T1
是活动协议,您可以在读卡之前等待 T0
协议的状态更改。
在互联网上搜索了很长时间后,我发现不需要对命令进行任何更改。
我只需要在传输的 read/open 命令末尾添加一个额外的零字节,并接收数据作为读取命令的响应,而不是使用单独的命令来接收字节。 (T=0 使用了 "request data/read data" 模型,而 T=1 似乎只是用数据响应)
我还需要更改所有提及的 SCARD_PCI_T0
以有条件地使用 SCARD_PCI_T1
并使 SCardConnect()
函数也接受 T1。
稍后我会post在这里提供一个不错的代码示例。