SCARD_W_RESET_CARD not returned by SCardTransmit()
SCardTransmit() do not work correctly on El Capitan (and maybe also on Yosemite but that is untested).When an application calls
SCardTransmit()
after the card has been reseted the returned value should be SCARD_W_RESET_CARD
to indicate that the card has been reseted.What happens on El Capitan is that the
SCardTransmit()
returns SCARD_S_SUCCESS
but the card answer will (in general) be incorrect since the card has been reseted.The error
SCARD_W_RESET_CARD
is returned from the next SCardTransmit()
call.This behaviour can confuse applications since the
SCardTransmit()
that should fail just works but with a (possibly) wrong answer from the card.See also
Apple bug report #23574394 "SCARD_W_RESET_CARD not returned by SCardTransmit()"Sample code
For the example I used a smart card with a test JavaCard applet loaded. The idea is to send commands to the applet. If the command is send before the applet is selected (after a reset) then the command will fail.I used my test applet installed in the card.
The 2 programs are written in Python and use the PySCard wrapper so the code is much shorter than if written in C-language.
Looping program
#! /usr/bin/env python from smartcard.System import readers from smartcard.util import toBytes # define the APDUs used in this script SELECT = toBytes("00 A4 04 00 06 A0 00 00 00 18 FF") COMMAND = toBytes("80 34 00 0E 0E") # use the 1st available reader reader = readers()[0] print "Using:", reader connection = reader.createConnection() connection.connect() data, sw1, sw2 = connection.transmit(SELECT) while True: data, sw1, sw2 = connection.transmit(COMMAND) print data print "Command: %02X %02X" % (sw1, sw2)
Reset program
#! /usr/bin/env python from smartcard.System import readers from smartcard.scard import SCARD_RESET_CARD reader = readers()[0] print "Using:", reader connection = reader.createConnection() connection.connect(disposition=SCARD_RESET_CARD)
Expected result (on Debian)
$ ./loop.py Using: Gemalto PC Twin Reader 00 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 Traceback (most recent call last): File "./loop2.py", line 20, indata, sw1, sw2 = connection.transmit(COMMAND) File "/usr/lib/python2.7/dist-packages/smartcard/CardConnectionDecorator.py", line 82, in transmit return self.component.transmit(bytes, protocol) File "/usr/lib/python2.7/dist-packages/smartcard/CardConnection.py", line 144, in transmit data, sw1, sw2 = self.doTransmit(bytes, protocol) File "/usr/lib/python2.7/dist-packages/smartcard/pcsc/PCSCCardConnection.py", line 198, in doTransmit SCardGetErrorMessage(hresult)) smartcard.Exceptions.CardConnectionException: Failed to transmit with protocol T0. Card was reset.
In another terminal I run the reset program:
$ ./reset.py Using: Gemalto PC Twin Reader
Result (on El Capitan)
$ ./loop.py Using: Gemalto PC Twin Reader [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13] Command: 90 00 [] Command: 69 85 Traceback (most recent call last): File "./loop2.py", line 20, indata, sw1, sw2 = connection.transmit(COMMAND) File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/CardConnectionDecorator.py", line 82, in transmit return self.component.transmit(bytes, protocol) File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/CardConnection.py", line 142, in transmit data, sw1, sw2 = self.doTransmit(bytes, protocol) File "/Library/Python/2.7/site-packages/pyscard-1.9.0-py2.7-macosx-10.10-intel.egg/smartcard/pcsc/PCSCCardConnection.py", line 205, in doTransmit SCardGetErrorMessage(hresult)) smartcard.Exceptions.CardConnectionException: Failed to transmit with protocol T0. Card was reset.
Results interpretation
In the two executions you see mostly the same results. The loop program runs and at one point it fails and returns with the error "Card was reset."The difference is that on El Capitan, just before returning with the error code, the program returned an error from the card "69 85". This is because the applet is not selected so the command is no more understood by the card. And the applet is no more selected because the card has been reseted.
The last command before the error should never have been sent to the card. That is the problem on El Capitan.