This is part of the series: "OS X El Capitan and smart cards: known bugs".
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, in
data, 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, in
data, 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.
Known workaround
None known.
Update: 26 September 2017
This bug is now fixed in macOS 10.13.0 High Sierra