FEATURE_CCID_ESC_COMMAND
Since revision 5991 my CCID driver does support FEATURE_CCID_ESC_COMMAND
and bPPDUSupport
.
These two services have been introduced in PC/SC v2 part 10 version 2.02.07 March 2010 and 2.02.08 April 2010.
FEATURE_CCID_ESC_COMMAND
This feature can be used to retrieve the control code to send a CCID escape command (PC_to_RDR_Escape
) to the reader using SCardControl()
.The value is returned by the
CM_IOCTL_GET_FEATURE_REQUEST
command. This will return a TLV data stream. The dwControlCode
to use is the value corresponding to the tag FEATURE_CCID_ESC_COMMAND
(0x13).Before this mechanism it was possible to use the value
IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE
but this value is not specified/documented in any official document (AFAIK).Using
FEATURE_CCID_ESC_COMMAND
is now portable (everywhere the PC/SC drivers implement it).bPPDUSupport
TheSCardControl()
function is quiet limited with the Microsoft CCID driver on Windows. So some smart card reader manufacturers use SCardTransmit()
to send commands to the reader (instead of the card).This mechanism is fragile since the reader must interpret the command and determine if the command if for itself or for the card.
The PC/SC workgroup documented a way to know how the driver is expecting to receive commands for itself.
bPPDUSupport
is a tag in the TLV data stream returned by FEATURE_GET_TLV_PROPERTIES
. The value is coded as:- Bit 0: If set to 1, PPDU is supported over
SCardControl()
usingFEATURE_CCID_ESC_COMMAND
- Bit 1: If set to 1, PPDU is supported over
SCardTransmit()
Implementation in my CCID driver
By default, for security reasons, sending an arbitraryPC_to_RDR_Escape
command is forbidden. This can be configured using the ifdDriverOptions
setting in the driver Info.plist
file.[...] <key>ifdDriverOptions</key> <string>0x0000</string> <!-- Possible values for ifdDriverOptions 1: DRIVER_OPTION_CCID_EXCHANGE_AUTHORIZED the CCID Exchange command is allowed. You can use it through SCardControl(hCard, IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE, ...) [...]If the bit 0 of
ifdDriverOptions
is set then the driver will allow the use of IOCTL_SMARTCARD_VENDOR_IFD_EXCHANGE
and now also the value associated to FEATURE_CCID_ESC_COMMAND
The driver will always report
bPPDUSupport
. By default the value is 0x00. But if If the bit 0 of ifdDriverOptions
is set then the value of bPPDUSupport
will be 0x01 indicating the support of FEATURE_CCID_ESC_COMMAND
using dwControlCode
and SCardControl()
.Sample code
The use of these features may be hard to understand. So a small example can help.In Python
#! /usr/bin/env python """ # FEATURE_CCID_ESC_COMMAND.py: Unitary test for FEATURE_CCID_ESC_COMMAND # Copyright (C) 2011 Ludovic Rousseau """ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, see <http://www.gnu.org/licenses/>. from smartcard.System import readers from smartcard.pcsc.PCSCPart10 import (SCARD_SHARE_DIRECT, SCARD_LEAVE_CARD, FEATURE_CCID_ESC_COMMAND, getFeatureRequest, hasFeature) def main(): """ main """ card_connection = readers()[0].createConnection() card_connection.connect(mode=SCARD_SHARE_DIRECT, disposition=SCARD_LEAVE_CARD) feature_list = getFeatureRequest(card_connection) ccid_esc_command = hasFeature(feature_list, FEATURE_CCID_ESC_COMMAND) if ccid_esc_command is None: raise Exception("The reader does not support FEATURE_CCID_ESC_COMMAND") # proprietary commands for Xiring readers version = [ord(c) for c in "VERSION"] res = card_connection.control(ccid_esc_command, version) print res print ''.join([chr(x) for x in res]) serial = [ord(c) for c in "GET_SN"] res = card_connection.control(ccid_esc_command, serial) print res print ''.join([chr(x) for x in res]) if __name__ == "__main__": main()
In C
The C language is much more verbose than Python. I added support ofFEATURE_CCID_ESC_COMMAND
and bPPDUSupport
in scardcontrol.c
example code provided with the CCID driver.The idea is the same as in Python:
- get the control code to use using
FEATURE_CCID_ESC_COMMAND
- use
SCardControl()
to send a command
Comments
PC/SC now documents a way to send arbitrary proprietary commands to a reader. We now have two questions:What command should you send?
You should know what you are doing and use the smart card reader user manual. So the command you want to use is documented, but maybe the documentation is not public. In general proprietary commands are not publicly documented.How to know what reader exactly you are using?
I do not have an answer to this question. Using the PC/SC reader name is fragile. See a previous blog article What is in a PC/SC reader name? The reader name can change over time like with "Gemplus" becoming "Gemalto".Maybe PC/SC must provide a new mechanism to report the USB VendorID and ProductID so that an application can be sure a specific reader is used.
Conclusion
Having to use proprietary commands is a sign of failure from the PC/SC workgroup. A service is needed but missing from the PC/SC standard. It has then been implemented using a proprietary mechanism (not documented, not portable, not interoperable).It is a failure because the application is now linked to a particular smart card reader model.