OS X Yosemite bug: SCardStatus() after a card reset
This is part of the series: "OS X Yosemite and smart cards: known bugs".
SCardStatus() after a card reset
SCardStatus() does not corectly detect card reset any more on OS X 10.10 Yosemite.If a card has been reseted using another PC/SC context then
SCardStatus()
will not fail with 0x80100068
(for SCARD_W_RESET_CARD
) as before but will succeed instead.The problem will be detected later by, for example, the next
SCardTransmit()
returning SCARD_W_RESET_CARD
.The problem is similar to the one described in OS X Yosemite bug: SCardBeginTransaction() after a card reset.
What is strange is that
SCardTransmit()
erroneously returns SCARD_W_RESET_CARD
after a SCardReconnect(..., SCARD_RESET_CARD, ...)
(see OS X Yosemite bug: SCardReconnect) but SCardStatus()
do not return SCARD_W_RESET_CARD
in the same case. The card reset (or not) state is managed in a "funny" way inside PC/SC on Yosemite.See also
Apple bug report #19264087 "PC/SC function SCardStatus() fails to fail after a card reset"#19264087 closed as a duplicate of #18689292.
Sample code
#include <stdio.h> #include <stdlib.h> #ifdef __APPLE__ #include <PCSC/winscard.h> #include <PCSC/wintypes.h> #else #include <winscard.h> #endif int main(int argc, const char * argv[]) { SCARDCONTEXT hContext; LPSTR mszReaders; DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); if (err != SCARD_S_SUCCESS) { printf("ScardEstablishedContext: 0x%08x\n",err); return -1; } DWORD cchReaders = 0; err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders); if (err != 0) { printf("ScardListReaders: 0x%08x\n",err); return -1; } mszReaders = calloc(cchReaders, sizeof(char)); if (!mszReaders) { printf("calloc\n"); return -1; } err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders); if (err != SCARD_S_SUCCESS) { printf("ScardListReaders: 0x%08x\n",err); return -1; } printf("Reader: %s\n", mszReaders); SCARDHANDLE hCard; DWORD dwActiveProtocol; err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol); if (err != SCARD_S_SUCCESS) { printf("ScardConnect: 0x%08x\n",err); return -1; } /* create a second PC/SC handle and reset the card */ SCARDHANDLE hCard2; err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard2, &dwActiveProtocol); if (err != SCARD_S_SUCCESS) { printf("ScardConnect: 0x%08x\n",err); return -1; } err = SCardDisconnect(hCard2, SCARD_RESET_CARD); if (err != SCARD_S_SUCCESS) { printf("SCardDisconnect: 0x%08x\n",err); } /* SCardStatus should fail with SCARD_W_RESET_CARD */ char name[100]; DWORD len = sizeof name; DWORD dwState, dwProtocol; unsigned char atr[MAX_ATR_SIZE]; DWORD atr_len = sizeof atr; err = SCardStatus(hCard, name, &len, &dwState, &dwProtocol, atr, &atr_len); if (err != SCARD_S_SUCCESS) { printf("SCardStatus: 0x%08x\n",err); return -1; } SCardDisconnect(hCard, SCARD_LEAVE_CARD); SCardReleaseContext(hContext); return 0; }
Result (on Yosemite)
$ CFLAGS="-framework PCSC" make main cc -framework PCSC main.c -o main
An error 0x80100068 (for SCARD_W_RESET_CARD) is expected here.
$ ./main Reader: Gemalto PC Twin Reader
Expected result (on Debian)
$ CFLAGS=`pkg-config --cflags libpcsclite` LDFLAGS=`pkg-config --libs libpcsclite` make main cc -pthread -I/usr/include/PCSC -lpcsclite main.c -o main
$ ./main Reader: Gemalto PC Twin Reader 00 00 SCardStatus: 0x80100068
Known workaround
None known.Modify your code to check for
SCARD_W_RESET_CARD
returned by SCardTransmit()
even after a successful SCardStatus()
.