Tuesday, May 18, 2010

How to know the PIN sizes supported by a pinpad reader?

The problem

Some pinpad readers (like the Gemalto PC pinpad v1) does not support PIN of less than 4 digits or more than 8 digits. The problem is that the Gemalto PC pinpad v1 reader is very strict and instead of ignoring unsupported options the reader reject the CCID command.

Here the application (OpenSC in this case) uses PC/SC v2 Part 10 to request a secure verify PIN (using SCardControl() with the ControlCode: 0x42330006.

Then the CCID driver creates a CCID Secure frame (PC_to_RDR_Secure = 0x69) and sends it to the reader. The reader returns an error on byte 15 which has the value 0x10 (or 16 in decimal) and is the first byte of the wPINMaxExtraDigit field (the second byte is 0x04). The reader does not support the value 16 for Maximum PIN size in digit.

The driver returns the generic error 612 (IFD_COMMUNICATION_ERROR) and PC/SC returns the error 0x80100016 (SCARD_E_NOT_TRANSACTED) to the application. The application has no way to know why the command failed. Someone has to look at the very low level logs to discover that the probelm is with wPINMaxExtraDigit.

The PC/SC solution: FEATURE_GET_TLV_PROPERTIES

Since PCSCv2 part 10 v2.02.07 from March 2010 a new feature is available: FEATURE_GET_TLV_PROPERTIES. It is very important to have a solution portable and documented in an "official" document. This feature is used to return a TLV formatted list of properties of the reader (or driver). Two properties are bMinPINSize and bMaxPINSize.

The only driver I know that supports FEATURE_GET_TLV_PROPERTIES is my CCID driver in version 1.3.12 release 8 May 2010. Maybe other drivers will support FEATURE_GET_TLV_PROPERTIES some time in the future.

Do not expect any thing from Microsoft. Their CCID driver and PCSC middleware are frozen in ice since some time (in years).

The sample codes

C code

If you use the sample code scardcontrol.c (772 lines of C) provided with my CCID driver you can see some results. For example with a Gemalto PC Pinpad v1 connected the output is:

getTlvProperties() returns a dictionnay. The entry for the "raw" key is just the complete buffer without interpretation.

Another related problem: bEntryValidationCondition

Another limitation of the Gemalto PC pinpad v1 is bEntryValidationCondition. This field is used by the PC_to_RDR_Secure command (verify and modify PIN) to tell what conditions shall be used by the reader to validate an entry. According to the CCID specification it can be:
The value is a bit wise OR operation.

01h Max size reached

02h Validation key pressed

04h Timeout occurred

But the Gemalto PC pinpad v1 only supports the 02h value (Validation key pressed). Any other value is rejected by the reader and the CCID command fails. The problem is that the PCSC application has no way to know what is supported by the reader.

Solution 1

So my CCID driver has a special treatment for this reader and bEntryValidationCondition is reset to 02h even if it is not what the applications requested.