Important!

Blog moved to https://blog.apdu.fr/

I moved my blog from https://ludovicrousseau.blogspot.com/ to https://blog.apdu.fr/ . Why? I wanted to move away from Blogger (owne...

Saturday, November 5, 2011

Extended APDU support reported by PC/SC

This is a proposition I submitted to the PC/SC workgroup for the November 2011 meeting.

I removed the people names from the document and used XXX instead.

Please send/add comments if you have some.



Extended APDU support reported by PC/SC




Extended APDU support reported by PC/SC

Authors: Ludovic ROUSSEAU
XXX, Xiring
Version: 1.0, October 2011

The problem

More and more cards do support extended APDU. Some card commands may be available only using an extended APDU.

It is not possible for a PC/SC application to know if the connected reader (+ driver) does or does not support extended APDU. The only way is to use SCardTransmit() to send an extended APDU and try to analyze the error code. Analysing an error code is difficult since PC/SC does nor define an error to indicate that the reader does not support extended APDU. So an already existing error code will be returned instead.

It is then hard or impossible for an application to report a clear error to a user like: "your reader does not support extended APDU. Please use another reader model." The error returned by PC/SC may be caused by another problem.

CCID

At the CCID level it is easy to know if a CCID reader does support extended APDU or not by interpreting the dwFeatures field in the USB CCID descriptor. Readers defined as "Short APDU level exchange with CCID" are not able to manage extended APDU. See http://pcsclite.alioth.debian.org/ccid_extended_apdu.html for more details and a list of readers in each categories.

The current proposal is to allow a PC/SC application to access this information at the PC/SC level.

Proposed solution using SCardControl()

Provide a new tag for FEATURE_GET_TLV_PROPERTIES to return the maximal size of data the reader (+ driver) can support.

For a reader supporting the full extended APDU size the value would be 0x10000 (64 kB). This size does not include the APDU header.

Tag name and value

Name:
dwMaxAPDUDataSize
Tag value:
0x0A
Length:
4 bytes
Coding:
as the other multi-bytes values returned by FEATURE_GET_TLV_PROPERTIES
Values:
  • 0: short APDU only
  • 0 < X <= 256: invalid values (RFU)
  • 256 < X <= 0x10000: short and extended APDU of up to X bytes of data
  • 0x10000 < X: invalid values (RFU)

Proposed solution using SCardGetAttrib()


As suggested by XXX I also propose to add a new entry in the table 3-1 in PC/SC part 3, chapter 3.1.1.2 'Enumeration of Device Capabilities'

I think the correct Information class is "Communications" so the tag should be the next free one: 0x0111.

The table should be updated to add a new line containing:
Information Class Data Element Tag Max Length Data Encoding
Communications Max APDU data size 0x0111 4 bytes DWORD

The PC/SC specification does not define the C macro name. But I propose to use:
#define SCARD_ATTR_MAX_APDU_DATA_SIZE
  SCARD_ATTR_VALUE(SCARD_CLASS_COMMUNICATIONS, 0x0111)
XXX from YYY commented this idea with, November 11 2010:
I fully agree that we should find this information in part 3.

However, it is not so nice to do this on Windows as the driver would have to intercept the IOCTL_SMARTCARD_GET_ATTRIBUTE request and treat it locally instead of forward it to SMCLIB via SmartcardDeviceControl (see http://msdn.microsoft.com/en-us/library/ff548899%28v=VS.85%29.aspx). Note that the driver cannot rely on error code returned by SmartcardDeviceControl to process the request as the IRP has already been completed.

That's why I would prefer using a PC/SC V2 feature for that. PC/SC V2 features such as IFD_PIN_PROPERTIES and IFD_DISPLAY_PROPERTIES are also reader capabilities and should be returned via part 3 but PC/SC structures are restricted in Windows to known fields without possibility to extend them easily.

So we have 2 choices:
  • Add this information in part 3 (and be quite inconsistent with IFD_PIN_PROPERTIES and IFD_DISPLAY_PROPERTIES) and do not strictly respect MS rules on PC/SC drivers
  • Add this information to part 10 as a PC/SC V2 feature
What is Microsoft point of view on that?

AFAIK Microsoft never commented on this remark.

This solution would work just fine using pcsc-lite (and without changing pcsc-lite, just the driver).

Since this solution may be difficult to implement on Windows it may not be a so good solution after all and FEATURE_GET_TLV_PROPERTIES should be used instead.

Sample in pseudo code

If an application need to use extended APDU for a card it should first check support of extended APDU and inform the user in case of problem.

if (get dwMaxAPDUDataSize failed)
{
    /* we don't know if extended APDU is supported */
    Shall we continue or abort? Maybe it is safer to continue (as before).
}
else
{
    if (dwMaxAPDUDataSize == 0)
    {
        error("your reader does not support extended APDU.")
        return
    }

    if (dwMaxAPDUDataSize < needed_size)
    {
        error("your reader supports too short extended APDU.")
        error("We need at least %d bytes", dwMaxAPDUDataSize)
        return
    }
}
continue execution

Questions & Answers

On/off state

It is not enough to have a on/off bit to indicate extended APDU support. Some reader may not support a full length extended APDU (64kB) but only a limited length (1kB or 4kB). So the feature must report the maximal size.

Short APDU

This proposal does not try to define what a "short APDU" or an "extended APDU" are. Short and extended APDU are already defined in ISO 7813-3 chapter 12.1.3 (page 33) "Decoding conventions for command APDUs" where cases 1, 2S, 2E, 3S, 3E, 4S and 4E are defined.

Test suite

This proposal does not plan to provide (or extend) a test suite for extended APDU.

Adding extended APDU support in the Microsoft test suite is another subject. I don't think Microsoft is interested in improving the test suite.

Case 4 APDU

The PC/SC specification does not specify if a case 4 APDU is supported or not by PC/SC.

Extended APDU are not restricted to case 4 APDU. But also exist for case 2 and 3. It is another matter to define the behavior of PC/SC with a case 4 APDU (4S or 4E).

Driver support of extended APDU

The driver must also support extended APDU.

Of course the reader and the driver (and the PC/SC middleware) must support extended APDU. The driver will report support of extended APDU only if the reader and the driver both do support extended APDU.

CCID does report extended APDU support

Yes, a CCID reader will report support (or not) of extended APDU. But a PC/SC application do not have access to this information. The purpose of this proposal is to allow a PC/SC application to get this information from the PC/SC layer.

Some non-CCID readers may also support extended APDU. The same mechanism can be used for non-CCID readers. The driver just need to implement the support of dwMaxAPDUDataSize in FEATURE_GET_TLV_PROPERTIES.

Switch the reader in TPDU mode

" In case your reader does not support extended APDU your driver can switch into TPDU mode and provide the APDU to the reader in several TPDUs. "

I do not know any documented/official CCID command to switch a reader from APDU to TPDU. Most readers can't be switched from APDU to TPDU. So this is not an option in most of the cases.

If a reader can be switched from APDU to TPDU and then support extended APDU this should be transparent for the application. It is the job of the driver to do whatever is needed and use dwMaxAPDUDataSize in FEATURE_GET_TLV_PROPERTIES to inform the application that extended APDU are available for this reader.

Use block chaining at the CCID level

" If the reader were a CCID-APDU styled reader, it is the task for the CCID driver to limit the buffers to: dwMaxCCIDMessageLength

All these single buffers can be chained in the CCID protocol, by using the chaining byte. "

CCID block chaining is available only for readers in "Short and Extended APDU level" mode. For readers in "Short APDU level" mode the wLevelParameter parameter of PC_to_RDR_XfrBlock in bChainParameter parameter of RDR_to_PC_DataBlock are RFU and must be 0 (according to CCID v1.1 section 6.1.4 PC_to_RDR_XfrBlock page 30 and 6.2.1 RDR_to_PC_DataBlock page 49).

Maybe the Microsoft CCID driver do use wLevelParameter/bChainParameter even for a "Short APDU level" reader. But this is not CCID compliant.

CCID block chaining is not available for "Short APDU level" readers.

Friday, October 28, 2011

Misc PC/SC proposals

In a previous post PC/SC workgroup, November 2011 meeting and on the MUSCLE mailing list I asked for suggestion to submit at the PC/SC workgoup planned for November 2011. I got some feedback. Here is the proposal I sent to the PC/SC workgroup.

Misc PC/SC proposals


Author: Ludovic Rousseau
Date: October 2011

Introduction

In October 2011 I asked on the MUSCLE mailing list (http://musclecard.com/list.html) what changes where expected by the PC/SC workgroup.

Here is a list of the items.

Changes in PC/SC workgroup documents

The PC/SC workgroup specifications contain a "Revision History" section with a brief description of the changes. It would be even better to have all the changes directly visible within the document.

This can be done using different processes:

PDF with revision marks

When a new document is provided by the PC/SC workgroup a second document with the changes (compared to the previous version of the document) can be provided. This second document is easy to generate using the "compare" feature of MS Word.

Provide the document in ODF format

If providing the second document with the changes is too much work for the process another solution is to provide the document in ODF (Open Document Format) format (in addition to the PDF format). With this format it is easy to use, for example, Libre Office and compare two versions of the same specification document.

Provide the document in .DOC format

If providing the documents in ODF format is too much work for the process another solution is to provide the document in MS .DOC format. I guess the original format of the specification is already .DOC so the only added step is to store the .DOC documents on the PC/SC workgroup web site.

Firewalled pinpad

Some pinpad readers implement a firewall. If a PIN Verify command (INS byte 0x20) is sent using SCardTransmit() the reader will reject it. With a firewalled pinpad the only way to verify a PIN is by using the secure verify PIN feature. The problem is that 2 different readers will return 2 different status word in case of firewall rejection. In the field we already have noted two different Status Word in this case: 0x6985 and 0x6D00.

According to ISO 7816-4 we have:
0x6D00:
Instruction code not supported or invalid
0x69xx:
Command not allowed (further qualification in SW2)
0x6985:
Conditions of use not satisfied

These values are not really correct. Another problem is that it is hard (or impossible) to know if the error is really a invalid INS code or a rejection by the firewall. Another option it to use an not already used value like 0x6404
0x64xx:
State of non-volatile memory is unchanged (further qualification in SW2)
Some special Status Word values are already used (in the field) with a pinpad:
SW Description
0x6400 Timeout
0x6401 Canceled by user
0x6402 PIN mismatch
0x6403 Too short or too long PIN

The PC/SC workgroup should define the status word (SW1 and SW2) to be reported by the reader in such a case. We propose to use 0x6404.

FEATURE_WRITE_DISPLAY

PC/SC v2 part 10 defines FEATURE_WRITE_DISPLAY. But I could not find how to implement it in the driver at the CCID level. I guess some reader manufacturers have implemented it using CCID proprietary extensions.
Proposal:
Document how FEATURE_WRITE_DISPLAY should or could be implemented at the CCID level

FEATURE_GET_KEY

PC/SC v2 part 10 defines FEATURE_GET_KEY. But I could not find how to implement it in the driver at the CCID level. I guess some reader manufacturers have implemented using CCID proprietary extensions.
Proposal:
Document how FEATURE_GET_KEY should or could be implemented at the CCID level

FEATURE_VERIFY_PIN_START

PC/SC v2 part 10 defines FEATURE_VERIFY_PIN_START, FEATURE_GET_KEY_PRESSED and FEATURE_VERIFY_PIN_FINISH. But I could not find how to implement it in the driver at the CCID level. I guess some reader manufacturers have implemented using CCID proprietary extensions.
Proposal:
Document how FEATURE_VERIFY_PIN_START, FEATURE_GET_KEY_PRESSED and FEATURE_VERIFY_PIN_FINISH should or could be implemented at the CCID level
The same issue also exists for FEATURE_MODIFY_PIN_START and FEATURE_MODIFY_PIN_FINISH.

Unblock PIN feature

Add the possibility to unblock a PIN code using a pinpad. The unblock INS code is 0x2C and defined by TS 51.011 EN (http://www.3gpp.org/ftp/Specs/html-info/51011.htm). Some pinpad reader do not accept INS=0x2C for a VERIFY PIN command.

I propose to accept at least:
INS byte Description
0x20 VERIFY command (ISO 7816-4)
0x2C UNBLOCK (3GPP TS 51.011 EN)
Proposal:
Document the minimum set of INS bytes that a pinpad reader shall accept for a secure verify PIN command.

PIN merge feature

Add a 'pin merge' feature in which: part of the PIN is provided by the application and the other part is entered on the pinpad reader. Some readers already allow this: you just put part of the PIN in the APDU -- but some readers seem to overwrite the APDU's PIN buffer with padding bytes.

For eID cards, it happens that a PUK is split between the citizen and the governement. The examples below come from an eID card with ASCII encoded PINs:

E.g. of a 'PIN unblock without PIN change', in this case you can do an SCardControl(ctrl-for-FEATURE_VERIFY_PIN_DIRECT , data) with:

data = 1E 1E 02 00 00 00 00 08 04 00 02 01 16 08 00 00 00 00 00 00 0D 00 00 00
          00 2C 01 81 08 FF FF FF FF 31 32 33 34  (37 bytes)

So the application provides the last part of the PUK (= "1234" in this case) and the pinpad reader should ask the first part of the PUK to the user and fill it in at the location of the FF FF FF FF.

So for ASCII and BCD encoded PINs, this trick works on readers that don't write padding bytes to the PIN buffer (i.e. they should not change the 31 32 33 34 into FF FF FF FF in the above example).

Another example, of a 'PIN unblock with PIN change', in this case you can do an SCardControl(ctrl-for-FEATURE_CHANGE_PIN_DIRECT , data) with

data = 1E 1E 02 00 00 00 08 08 04 03 02 03 16 08 00 00 00 00 00 00 15 00 00 00
          00 2C 00 81 10 FF FF FF FF 31 32 33 34 FF FF FF FF FF FF FF FF  (45 bytes)

Here again, the first FF FF FF FF are for the user's part of the PUK, and the last 8 FF bytes are for the new PIN. Same remarks as above apply.

Conclusion

PC/SC defines some services at the PC/SC layer. This is fine. But the CCID specification does not provide any documentation or specification for these services.

A documentation is needed so that these services can be implemented in a "class" CCID driver.

Updating the CCID specification may be a difficult task. So I propose to host the documentation in the PC/SC workgroup. I do not ask to add the documentation in an existing document, just to host the documentation in a central place.

One easy solution is to host the CCID level programing manual of readers implementing the solutions we described above.

Thursday, October 13, 2011

http://musclecard.com/ is gone (for now)

The domain name musclecard.com has expired. The web site is now a domain parking web site.

Effects

  • The mailing list muscle@lists.musclecard.com is no more working
  • The web site http://musclecard.com/ is unavailable. But the same web site http://linuxnet.com/ is still working

I tried to contact David Corcoran, original author of pcsc-lite and maintainer of the web site. But as expected some of his emails are no more valid. David was not very active on the list since some time now.

New list

I created a new list on the pcsclite project on alioth: pcsclite-muscle

Conclusion


If the domain musclecard.com does not come back we will have to migrate to the new list.
I will keep you informed.

[update]

Oct 16th, 2011

The domain is now back online. It looks like the auto-renew failed due to an old credit card. David Corcoran renewed it for 3 more years. Thanks David!

Tuesday, October 11, 2011

New version of libccid: 1.4.5

I just released a new version of libccid.

Changelog

1.4.5 - 11 October 2011, Ludovic Rousseau
  • Add support of Alcor Micro AU9540, Ubisys 13.56MHz RFID (CCID),
    BIFIT USB-Token iBank2key, BIFIT iBank2Key, Gemalto Ezio Shield
    PinPad reader, Gemalto SA .NET Dual, Precise Sense MC reader (with
    fingerprint), SDS DOMINO-Key TWIN Pro
  • Add support of bPPDUSupport and FEATURE_CCID_ESC_COMMAND
  • SCARD_ATTR_VENDOR_NAME and SCARD_ATTR_VENDOR_IFD_VERSION are not
    the vendor name and version of the driver but of the IFD:
    InterFace Device i.e. the smart card reader. We then return the
    USB iManufacturer string as SCARD_ATTR_VENDOR_NAME and USB
    bcdDevice as SCARD_ATTR_VENDOR_IFD_VERSION
  • reduce binary size bu removing unused features from simclist
  • Fix some warnings reported bu Coverity

Sunday, October 9, 2011

PC/SC workgroup, November 2011 meeting

2 times a year the PC/SC workgroup is having a meeting.

When and Where?

The next meeting is planned on November 15th 2011 during the "Cartes & Identification" international event in Paris, France.

Who?

The members of the PC/SC workgoup are mainly smart card and reader manufacturers.

Core Members:

  • Gemalto
  • Oracle

Associate Members:

  • Advanced Card Systems
  • Athena Smartcard Solutions
  • C3PO S.A.
  • Cherry /ZF Electronics GmbH
  • HID Global
  • Infineon
  • Kobil Systems GmbH
  • NXP Semiconductors
  • O2Micro, Inc.
  • Realtek Semiconductor Corp.
  • Sagem Monetel GmbH
  • SCM Microsystems
  • Siemens
  • Todos
  • Toshiba
  • Xiring

One particularly missing member is Microsoft. Microsoft was a core member for a long time but has now disappeared from the PCSC workgoup list.

Me

Since 1 year I am an invited member of the PC/SC workgroup as a Free Software member and author of pcsc-lite and libccid. In practice I am (just) on one of the PC/SC workgroup mailing list. This list is very quiet since nearly everything is discussed and resolved during the 2 meetings each year.

You

If you are not a member of the PC/SC workgroup you can't change the standard. But you may have good ideas for a new and missing feature.
For example the FEATURE_GET_TLV_PROPERTIES service is something that was added in March 2010 after a proposal I made with the help of Gemalto. So an evolution of the standard is possible.

If, as an PC/SC application author, you think something is missing in the PC/SC standard just tell me. I will try to propose it for inclusion.

Conclusion

Please share your good ideas about the evolution of PC/SC.

Wednesday, October 5, 2011

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

The SCardControl() 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() using FEATURE_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 arbitrary PC_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 of FEATURE_CCID_ESC_COMMAND and bPPDUSupport in scardcontrol.c example code provided with the CCID driver.

The idea is the same as in Python:
  1. get the control code to use using FEATURE_CCID_ESC_COMMAND
  2. use SCardControl() to send a command
The C source code is 817 lines long. It is available online.

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.

pcsclite subversion revision 6000

Celebration

I just committed revision 6000 in the pcsclite project :-)

History

Previous notable revisions were:
5000 in 16 June 2010
4000 in 5 October 2007
3000 in 14 June 2008
2000 in 14 April 2006
1000 in 30 June 2004

Maybe you have noted that revision 4000 is dated before revision 3000. I think this is because of the conversion from CVS to SVN. The change occurred between revision 3502 (10 May 2009) and 3503 (2 Jul 2001).

The commit message for 3503 is: "Standard project directories initialized by cvs2svn."