The 10.10.2 release of Yosemite solves some of the PC/SC bugs introduced in 10.10 and I reported in "OS X Yosemite and smart cards: known bugs".
I updated the main article with the list and also each individual bug documentation.
Maybe the 10.10.3 release will solve the other PC/SC bugs.
Thursday, February 26, 2015
Monday, February 23, 2015
Debug a smart card application on Yosemite
In the previous article "Debug a smart card reader driver on Yosemite" I wrote about how to get some log from a new version of my CCID driver.
As documented the activation of APDU logging is easy. Just do (on 1 line):
A new file/Library/Preferences/com.apple.security.smartcard.plist will be created.
You can display the .plist file using Xcode for example. But you can't edit it directly with Xcode since the file can only be updated by root.
You can get the logging status using:
com.apple.ifdreader then the value is reset to no logging.
To see that just do:
This is very smart idea. It will prevent you from forgeting to disable logging after use. You can be sure that the logging will be disabled after a reboot or at the next USB reader connection and no secret PIN code will be stored in your log file without you explicitly requesting it.
foo contains the log lines I use the combination:
You can see that the card in inserted at 19:54:53, the log is "card in" And 5 seconds later the card is power off, the log line is "unpower". This is what I already explained in "OS X Yosemite bug: SCardTransmit returns SCARD_W_UNPOWERED_CARD".
/Library/Preferences/com.apple.security.smartcard.plist the situation is not less secure than what I presented in "Debug a smart card reader driver on Yosemite" since you also needed to have the same administration privilege (be root) to edit the driver configuration file /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist .
Maybe I should add a similar feature in pcsc-lite for GNU/Linux. What do you think?
APDU logging from Apple
After I wrote the previous article Dustin N. told me that Apple now provides a logging facility for APDUs.SmartCardServices.7
The SmartCardServices manpage says (online HTML version at SmartCardServices):
SMARTCARDSERVICES(7) BSD Miscellaneous Information Manual SMARTCARDSERVICES(7)
NAME
SmartCardServices — overview of smart card support
DESCRIPTION
The SmartCardServices is a set of components which add native support for smart cards
to operating system. Supported smart cards appear as separate keychains.
to operating system. Supported smart cards appear as separate keychains.
USB SMART CARD READER DRIVERS
OS X has built-in support for USB CCID class-compliant smart card readers. For other
readers, install the reader driver in /usr/libexec/SmartCardServices/drivers. Each driver
is a bundle. The bundle contains an XML file Info.plist which contains the device’s USB vendor ID and product ID. For detailed description of plist format and how to write driver, see <http://pcsclite.alioth.debian.org/api/group__IFDHandler.html>
readers, install the reader driver in /usr/libexec/SmartCardServices/drivers. Each driver
is a bundle. The bundle contains an XML file Info.plist which contains the device’s USB vendor ID and product ID. For detailed description of plist format and how to write driver, see <http://pcsclite.alioth.debian.org/api/group__IFDHandler.html>
SMART CARD APDU LOGGING
It is possible to turn on logging for smart cards. Logging is turned on by setting global preference:
sudo defaults write /Library/Preferences/com.apple.security.smartcard Logging -bool yes
After a smart card reader is connected (or after reboot) all operations including contents of sent and received APDU messages are then logged into system log. Logging uses facility com.apple.security.smartcard.log so it is possible to set up filtering of these logs into custom targets (see asl.conf(5)) Note that logging setting is one-shot; it must be turned on by the command above to start logging again with a new reader. This is to avoid security risk that logging is turned on indefinitely.
SEE ALSO
sc_auth(8), defaults(1), asl.conf(5)
Mac OS X August 5, 2014 Mac OS X
Configuration
As documented the activation of APDU logging is easy. Just do (on 1 line):
$ sudo defaults write /Library/Preferences/com.apple.security.smartcard Logging -bool yes
A new file
You can display the .plist file using Xcode for example. But you can't edit it directly with Xcode since the file can only be updated by root.
$ ls -l /Library/Preferences/com.apple.security.smartcard.plist -rw-r--r-- 1 root wheel 55 23 fév 10:09 /Library/Preferences/com.apple.security.smartcard.plist
You can get the logging status using:
$ defaults read /Library/Preferences/com.apple.security.smartcard Logging 1You do not need to be root to read the logging status.
First time only
As indicated in the manpage documentation, you can note that the logging activation is only one shoot. Once the logging state has been read and activated byTo see that just do:
- Activate logging
$ sudo defaults write /Library/Preferences/com.apple.security.smartcard Logging -bool yes
- Read logging state
$ defaults read /Library/Preferences/com.apple.security.smartcard Logging 1
- Plug in a USB reader
- Read logging state again
$ defaults read /Library/Preferences/com.apple.security.smartcard Logging 0
This is very smart idea. It will prevent you from forgeting to disable logging after use. You can be sure that the logging will be disabled after a reboot or at the next USB reader connection and no secret PIN code will be stored in your log file without you explicitly requesting it.
Sample output
As in "Debug a smart card reader driver on Yosemite" I used a combination of lwatch and ansi2html. If the file$ lwatch -i - < foo | ansi2html -i
$ syslog -w -k Sender com.apple.ifdreader Feb 23 19:54:49 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: logging slot 'Gemalto PC Twin Reader' Feb 23 19:54:53 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: card in Feb 23 19:54:53 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: ATR:3b fa 94 00 00 81 31 20 43 80 65 a2 01 01 01 3d 72 d6 43 21 Feb 23 19:54:58 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: unpower Feb 23 19:54:59 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: ATR:3b fa 94 00 00 81 31 20 43 80 65 a2 01 01 01 3d 72 d6 43 21 Feb 23 19:54:59 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: T=1 Feb 23 19:54:59 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: APDU ->:00 a4 04 00 0a a0 00 00 00 62 03 01 0c 06 01 Feb 23 19:54:59 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: APDU <-:90 00 Feb 23 19:54:59 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: APDU ->:00 00 00 00 Feb 23 19:54:59 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: APDU <-:48 65 6c 6c 6f 20 77 6f 72 6c 64 21 90 00 Feb 23 19:55:04 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: unpower Feb 23 19:55:07 iMac-de-Ludovic.local com.apple.ifdreader[586] <Notice>: card out
You can see that the card in inserted at 19:54:53, the log is "card in" And 5 seconds later the card is power off, the log line is "unpower". This is what I already explained in "OS X Yosemite bug: SCardTransmit returns SCARD_W_UNPOWERED_CARD".
Security
Since you need to have the administration privilege (be root) to edit the fileConclusion
Apple provides a nice way to get the card ATR, APDU sent to the card and response from a smart card reader.Maybe I should add a similar feature in pcsc-lite for GNU/Linux. What do you think?
Thursday, February 19, 2015
Using cron on Mac OS X
This article is not about smart card. I wrote it to remember how to do and, possibly, help other Mac OS X users.
Mac OS X is a Unix system and so can be used as a Unix system with all the normal commands and services found on a Unix system.
I discovered recently that every thing was installed to use cron on my Mavericks (10.9) system.
This command will send the time and date in an email to rousseau with subject "test".
You should not have any output from the command unless you get an error.
If your mail server require an user authentication you may need to configure your Postfix local configuration.
Here we can read our test email. Then delete it using the "
~/.forward file. This file should contain the email you want to redirect your emails to:
Test again to send you an email and check the redirection is working.
The problem with vi (or vim) is that vi exits with a return value that is considered as an error by crontab:
A solution found at "Error adding cronjobs in Mac OS X Lion" is to use nano instead of vi:
But I do not like nano and really prefer vim. So another way to solve that is to create a file (you may use the TextEdit graphical application to edit the file but take care to use the Text and not RTF format). I named my filecrontab so that vim will do syntax colorization for me.
Then install it using:
Check your configuration has been accepted using:
Read the crontab section 5 manual page (
Mac OS X is and stays a Unix system under the graphical interface.
Mac OS X is a Unix system and so can be used as a Unix system with all the normal commands and services found on a Unix system.
I discovered recently that every thing was installed to use cron on my Mavericks (10.9) system.
cron - daemon to execute scheduled commands
The goal of cron is to run commands periodically. For example your can start a backup command or a Jenkins job on a regular schedule.Mail configuration
cron sends its output and error messages by email. So you need to have your email configured correctly.Sending an email
By default email is already working on Mac OS X for a local delivery. You can check it using:$ date | mail -s test rousseauOf course you use your own login name instead of rousseau.
This command will send the time and date in an email to rousseau with subject "test".
You should not have any output from the command unless you get an error.
If your mail server require an user authentication you may need to configure your Postfix local configuration.
Reading an email
The same commandmail
can be used to read emails stored locally.$ mail Mail version 8.1 6/6/93. Type ? for help. "/var/mail/rousseau": 1 message 1 new >N 1 rousseau@iMac-de-Lud Sun Feb 15 13:30 14/538 "test" ? press Enter Message 1: From rousseau@iMac-de-Ludovic.local Sun Feb 15 13:30:01 2015 X-Original-To: rousseau Delivered-To: rousseau@iMac-de-Ludovic.local To: rousseau@iMac-de-Ludovic.local Subject: test Date: Sun, 15 Feb 2015 13:30:01 +0100 (CET) From: rousseau@iMac-de-Ludovic.local (Ludovic Rousseau) Dim 15 fév 2015 13:30:01 CET ? d ? q $
Here we can read our test email. Then delete it using the "
d
" command and quit using the "q
" command.Redirecting your emails
Maybe you do not read your email using themail
command on your Mac, me neither. You can redirect your emails using the standard Unix way: a $ cat ~/.forward ludovic.rousseau@free.fr
Test again to send you an email and check the redirection is working.
Cron configuration
cron uses a crontab to store the user configuration. Each user has its own crontab configuration. Use the shell commandcrontab
to edit the configuration.vi
crontab uses the editor configured in the EDITOR environment variable or vi by default.The problem with vi (or vim) is that vi exits with a return value that is considered as an error by crontab:
$ crontab -e crontab: "vi" exited with status 1And all your edition is lost.
A solution found at "Error adding cronjobs in Mac OS X Lion" is to use nano instead of vi:
$ EDITOR=nano crontab -e
But I do not like nano and really prefer vim. So another way to solve that is to create a file (you may use the TextEdit graphical application to edit the file but take care to use the Text and not RTF format). I named my file
$ cat Documents/crontab # Every hour 0 * * * * echo "pouet"
Then install it using:
$ crontab Documents/crontab
Check your configuration has been accepted using:
$ crontab -l # Every hour 0 * * * * echo "pouet"
Read the crontab section 5 manual page (
man 5 crontab
) to know the format to use.Conclusion
No need to install a graphical tool to periodically run a command on Mac OS X.Mac OS X is and stays a Unix system under the graphical interface.
Friday, February 13, 2015
Debug a smart card reader driver on Yosemite
Since Mac OS X Yosemite (10.10) the pcscd command is no more present. See "OS X Yosemite and smart cards status" for more details.
The problem is that I used this command to get some debug log from my CCID smart card driver. See "pcscd debug output on Mac OS X". Unfortunately this technique is no more available.
/System/Library/CryptoTokenKit/com.apple.ifdreader.slotd/Contents/MacOS/com.apple.ifdreader father process is process 1. Process 1 is launchd "System wide and per-user daemon/agent manager".
If I start the command from a Terminal I get no error message, the command does not return but in the/var/log/system.log file I find:
So I think some parameters and/or context is missing.
The process is started by launchd. The configuration file is/System/Library/LaunchDaemons/com.apple.ifdreader.plist . It contains:
com.apple.ifdreader process.
First you need to stop the process. You can use:
Then you need to restart it. Since most smart card reader are USB devices you just need to plug your USB reader andcom.apple.ifdreader is (re)started automatically.
I modified my CCID driver to log messages using
We have two options on Mac OS X: a graphical application or a command line tool.
/Applications/Utilities/Console.app .
The application icon is:
The application is easy to use. You can filter the output to only have logs from ifdreader.
Arguments:
I added a new option to the CCID driver to log this information. Since it is a sensitive information (you can see the PIN code sent to the card for example) you need the administrative privilege and edit the driver configuration fileInfo.plist . The configuration file should be /usr/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist .
The new option value is 0x0080. You should have some thing like:
You will get something like:
You can note that the card power up failed 3 times.
The log criticality is available. The default level is <Warning> but can be <Error> or <Critical>.
The problem is that I used this command to get some debug log from my CCID smart card driver. See "pcscd debug output on Mac OS X". Unfortunately this technique is no more available.
com.apple.ifdreader
TheIf I start the command from a Terminal I get no error message, the command does not return but in the
Feb 10 14:49:57 imac com.apple.ifdreader[37446]: assertion failed: 14C109: libxpc.dylib + 34612 [876216DC-D5D3-381E-8AF9-49AE464E5107]: 0x2d Feb 10 14:49:57 imac com.apple.ifdreader[37446]: Bogus event on event stream listener.
So I think some parameters and/or context is missing.
The process is started by launchd. The configuration file is
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.apple.ifdreader</string> <key>RunAtLoad</key> <false/> <key>EnablePressuredExit</key> <true/> <key>POSIXSpawnType</key> <string>Adaptive</string> <key>ProgramArguments</key> <array> <string>/System/Library/CryptoTokenKit/com.apple.ifdreader.slotd/Contents/MacOS/com.apple.ifdreader</string> </array> <key>LaunchEvents</key> <dict> <key>com.apple.iokit.matching</key> <dict> <key>com.apple.ctk.ifdreader.device</key> <dict> <key>IOMatchLaunchStream</key> <true/> <key>IOProviderClass</key> <string>IOUSBDevice</string> </dict> </dict> </dict> </dict> </plist>
Restarting com.apple.ifdreader
After you changed the driver configuration it may be needed to restart theFirst you need to stop the process. You can use:
$ sudo killall -SIGKILL -m .*com.apple.ifdreader
Then you need to restart it. Since most smart card reader are USB devices you just need to plug your USB reader and
Send logs using syslog(3)
Ifprintf(3)
can't be used to log messages then the normal option for a daemon is to use syslog(3)
.I modified my CCID driver to log messages using
syslog(3)
. This feature will be available in the CCID driver versions 1.4.19 and later.Get syslog logs
Now that the messages from the CCID driver are sent somewhere we must get them.We have two options on Mac OS X: a graphical application or a command line tool.
Console application
Apple provides the Console application inThe application icon is:
The application is easy to use. You can filter the output to only have logs from ifdreader.
syslog -k Sender com.apple.ifdreader
Another opiont is to use the command line toolsyslog(1)
.$ syslog -w -k Sender com.apple.ifdreader
Arguments:
- -w
The -w option causes syslog to wait for new messages. By default, syslog
prints the last 10 messages, then waits for new messages to be added to
the data store. - -k
The -k option may be followed by one, two, or three arguments. A single
argument causes a match to occur if a message has the specified key,
regardless of value. If two arguments are specified, a match occurs when
a message has exactly the specified value for a given key. For example,
to find all messages sent by the portmap process:
syslog -k Sender portmap
Sample output
I used lwatch to add colors and ansi2html to convert the ANSI color codes to HTML.Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 08676368 ifdhandler.c:96:CreateChannelByNameOrChannel() Lun: 0, device: Gemalto PC Twin Reader Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000110 ccid_usb.c:283:OpenUSBByName() Using: /usr/libexec/SmartCardServices/drivers/ifd-ccid-test-test.bundle/Contents/Info.plist Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000637 ccid_usb.c:301:OpenUSBByName() ifdManufacturerString: Ludovic Rousseau (ludovic.rousseau@free.fr) Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000089 ccid_usb.c:302:OpenUSBByName() ifdProductString: Generic CCID driver Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000075 ccid_usb.c:303:OpenUSBByName() Copyright: This driver is protected by terms of the GNU Lesser General Public License version 2.1, or (at your option) any later Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00177567 ccid_usb.c:595:OpenUSBByName() Found Vendor/Product: 08E6/3437 (Gemalto PC Twin Reader) Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000078 ccid_usb.c:597:OpenUSBByName() Using USB bus/device: 253/6 Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000063 ccid_usb.c:649:OpenUSBByName() bNumDataRatesSupported is 0 Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00010058 commands.c:997:CmdEscapeCheck error on byte 10 Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000082 ccid.c:215:set_gemalto_firmware_features() GET_FIRMWARE_FEATURES failed: 612, len=0 Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000067 ifdhandler.c:375:IFDHGetCapabilities() tag: 0xFAD, Gemalto PC Twin Reader (lun: 0) Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000072 ifdhandler.c:375:IFDHGetCapabilities() tag: 0x7A007, Gemalto PC Twin Reader (lun: 0) Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000072 ifdhandler.c:375:IFDHGetCapabilities() tag: 0xFAE, Gemalto PC Twin Reader (lun: 0) Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00000095 ifdhandler.c:463:IFDHGetCapabilities() Reader supports 1 slot(s) Feb 13 14:04:02 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 00001257 ifdhandler.c:1139:IFDHPowerICC() action: Reset, Gemalto PC Twin Reader (lun: 0) Feb 13 14:04:09 iMac-de-Ludovic.local com.apple.ifdreader[6581] <Warning>: 06859987 ifdhandler.c:1139:IFDHPowerICC() action: Reset, Gemalto PC Twin Reader (lun: 0)
ATR and APDU logging
Using pcscd it was possible to log APDU sent to the card and the response from the card. This service is now missing since pcscd is no more present.I added a new option to the CCID driver to log this information. Since it is a sensitive information (you can see the PIN code sent to the card for example) you need the administrative privilege and edit the driver configuration file
The new option value is 0x0080. You should have some thing like:
<key>ifdDriverOptions</key> <string>0x0080</string>
You will get something like:
Feb 13 15:17:04 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 00000076 ifdhandler.c:463:IFDHGetCapabilities() Reader supports 1 slot(s) Feb 13 15:17:11 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 06637507 ifdhandler.c:1139:IFDHPowerICC() action: Reset, Gemalto PC Twin Reader (lun: 0) Feb 13 15:17:11 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Error>: 00055035 commands.c:249:CmdPowerOn Card absent or mute Feb 13 15:17:11 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Critical>: 00000171 ifdhandler.c:1206:IFDHPowerICC() PowerUp failed Feb 13 15:17:15 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 04106934 ifdhandler.c:1139:IFDHPowerICC() action: Reset, Gemalto PC Twin Reader (lun: 0) Feb 13 15:17:15 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Error>: 00055041 commands.c:249:CmdPowerOn Card absent or mute Feb 13 15:17:15 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Critical>: 00000184 ifdhandler.c:1206:IFDHPowerICC() PowerUp failed Feb 13 15:17:17 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 02376603 ifdhandler.c:1139:IFDHPowerICC() action: Reset, Gemalto PC Twin Reader (lun: 0) Feb 13 15:17:17 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Error>: 00055065 commands.c:249:CmdPowerOn Card absent or mute Feb 13 15:17:17 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Critical>: 00000146 ifdhandler.c:1206:IFDHPowerICC() PowerUp failed Feb 13 15:17:19 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 01725812 ifdhandler.c:1139:IFDHPowerICC() action: Reset, Gemalto PC Twin Reader (lun: 0) Feb 13 15:17:19 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: ATR: 3B FA 94 00 00 81 31 20 43 80 65 A2 01 01 01 3D 72 D6 43 21 Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 03997665 ifdhandler.c:682:IFDHSetProtocolParameters() protocol T=1, Gemalto PC Twin Reader (lun: 0) Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 00000099 ifdhandler.c:2073:extra_egt() Extra EGT patch applied Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 00040776 ifdhandler.c:1286:IFDHTransmitToICC() Gemalto PC Twin Reader (lun: 0) Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: APDU: 00 A4 04 00 0A A0 00 00 00 62 03 01 0C 06 01 Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: SW: 90 00 Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 00015578 ifdhandler.c:1286:IFDHTransmitToICC() Gemalto PC Twin Reader (lun: 0) Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: APDU: 00 00 00 00 Feb 13 15:17:23 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: SW: 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 90 00 Feb 13 15:17:24 iMac-de-Ludovic.local com.apple.ifdreader[11365] <Warning>: 01039858 ifdhandler.c:1139:IFDHPowerICC() action: PowerDown, Gemalto PC Twin Reader (lun: 0)
You can note that the card power up failed 3 times.
The log criticality is available. The default level is <Warning> but can be <Error> or <Critical>.
Conclusion
Getting debug logs of the PC/SC layer is sometimes important to find a problem. I had to modify my CCID driver to add a new log mechanism that works on Yosemite.[UPDATE]
The ATR and APDU logging is no more needed. See "Debug a smart card application on Yosemite".[UPDATE 2]
You can change the log level of the com.apple.ifdreader process. See "Change syslog logging level on Yosemite".Monday, February 9, 2015
OS X Yosemite bug: SCardTransmit returns SCARD_W_UNPOWERED_CARD
This is part of the series: "OS X Yosemite and smart cards: known bugs".
The card auto power off feature is visible with some smart card readers, like the Gemalto PC Twin (renamed PC USB TR and then renamed IDBridge CT30).
The reader has a LED in it. If the LED blinks then the reader is powered. If the LED is ON then the smart card is powered.
On Mavericks (and the previous versions of Mac OS X) when you insert a card the LED is ON (unless the reader driver is not found) and stays ON until you remove the card.
On Yosemite when you insert a smart card the LED is ON and after 5 seconds the LED blinks. This indicates that the card is powered for 5 seconds and then the card is powered off. Great.
After the 5 seconds delay the second application will get a SCARD_W_UNPOWERED_CARD error on the next SCardTransmit() call.
It looks like Apple forgot to power off the card only if NO other PC/SC application is using the card, not just after the first
The
The bug has been closed by Apple on 8th April 2015 as fixed in 10.10.3.
Since this sample code needs two programs you need to have two Terminal windows opened.
In the first terminal you run
Once the second execution has finished you press enter in the first terminal to continue the execution of the first program.
One very bad (and untested) solution would be to create an application that sends an APDU (with no side effect) every 3 or 4 seconds so that the 5 seconds delay never occurs. But that is a very very bad solution. And it may be difficult or impossible to find an APDU that would be safe to send at any time.
SCardTransmit
SCardTransmit() do not work reliably any more on Yosemite. In some cases using 2 PC/SC applications the functions returns SCARD_W_UNPOWERED_CARD (or0x0x80100067
).Interpretation
My interpretation is that Apple tried to implement a card auto power off mechanism. I added this feature in pcsc-lite version 1.6.5 from 2010. See "Card auto power on and off".The card auto power off feature is visible with some smart card readers, like the Gemalto PC Twin (renamed PC USB TR and then renamed IDBridge CT30).
The reader has a LED in it. If the LED blinks then the reader is powered. If the LED is ON then the smart card is powered.
On Mavericks (and the previous versions of Mac OS X) when you insert a card the LED is ON (unless the reader driver is not found) and stays ON until you remove the card.
On Yosemite when you insert a smart card the LED is ON and after 5 seconds the LED blinks. This indicates that the card is powered for 5 seconds and then the card is powered off. Great.
Bug
The problem is that the Apple code is bogus. When 2 PC/SC applications are using the smart smart card at the same time the 5 seconds delay before powering off the card is started when the first application releases the card, even if the second application still has an access to the smart card.After the 5 seconds delay the second application will get a SCARD_W_UNPOWERED_CARD error on the next SCardTransmit() call.
It looks like Apple forgot to power off the card only if NO other PC/SC application is using the card, not just after the first
SCardDisconnect()
.The
sleep(5)
in the sample code is important. This is the delay needed for the PC/SC layer to decide to power off the card. You can also remove this delay and wait before you press enter to continue the first execution.See also
Apple bug report #19764910 "PC/SC: SCardTransmit returns SCARD_W_UNPOWERED_CARD"The bug has been closed by Apple on 8th April 2015 as fixed in 10.10.3.
Sample code
#include <stdio.h> #include <stdlib.h> #include <unistd.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 : %08x\n",err); return -1; } DWORD cchReaders = 0; err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders); if (err != 0) { printf("ScardListReaders : %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 : %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 : %08x\n",err); return -1; } unsigned char cmd[] = {0, 0, 0, 0, 0}; unsigned char resp[255]; DWORD resp_len; SCARD_IO_REQUEST *pci; if (SCARD_PROTOCOL_T0 == dwActiveProtocol) pci = SCARD_PCI_T0; else pci = SCARD_PCI_T1; resp_len = sizeof resp; err = SCardTransmit(hCard, pci, cmd, sizeof cmd, NULL, resp, &resp_len); if (err != SCARD_S_SUCCESS) { printf("ScardTransmit: %08x\n",err); return -1; } printf("SCardTransmit: %0X\n", err); if (1 == argc) { printf("Run the second instance\n"); getchar(); } resp_len = sizeof resp; err = SCardTransmit(hCard, pci, cmd, sizeof cmd, NULL, resp, &resp_len); if (err != SCARD_S_SUCCESS) { printf("ScardTransmit: %08x\n",err); return -1; } printf("SCardTransmit: %0X\n", err); SCardDisconnect(hCard, SCARD_LEAVE_CARD); SCardReleaseContext(hContext); if (argc > 1) { /* The sleeping time is important here */ sleep(5); printf("Continue the first instance\n"); } return 0; }
Result (on Yosemite)
$ CFLAGS="-framework PCSC" make main cc -framework PCSC main.c -o main
Since this sample code needs two programs you need to have two Terminal windows opened.
In the first terminal you run
./main
and in the second terminal you run ./main a
(with an argument).Once the second execution has finished you press enter in the first terminal to continue the execution of the first program.
1st terminal | 2nd terminal |
$ ./main Reader : Gemalto PC Twin Reader SCardTransmit: 0 Run the second instance | |
$ ./main a Reader : Gemalto PC Twin Reader SCardTransmit: 0 SCardTransmit: 0 Continue the first instance | |
ScardTransmit: 80100067 |
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
1st terminal | 2nd terminal |
$ ./main Reader : Gemalto PC Twin Reader SCardTransmit: 0 Run the second instance | |
$ ./main a Reader : Gemalto PC Twin Reader SCardTransmit: 0 SCardTransmit: 0 Continue the first instance | |
ScardTransmit: 0 |
Known workaround
None known.One very bad (and untested) solution would be to create an application that sends an APDU (with no side effect) every 3 or 4 seconds so that the 5 seconds delay never occurs. But that is a very very bad solution. And it may be difficult or impossible to find an APDU that would be safe to send at any time.