macOS Sonoma bug: SCardControl() (part 2)

In macOS Sonoma bug: SCardControl() returns SCARD_E_NOT_TRANSACTED I presented the problems with SCardControl() on macOS Sonoma. Then in Apple's own CCID driver in Sonoma we saw that macOS Sonoma provides two CCID drivers: one from Apple and one from me.

In Sonoma version 14.3 the situation evolved. The bug described in macOS Sonoma bug: SCardControl() returns SCARD_E_NOT_TRANSACTED is mostly fixed.

Switch CCID driver

It is easy to switch between Apple CCID driver and my CCID driver.

To enable my CCID driver you do:

sudo defaults write /Library/Preferences/com.apple.security.smartcard useIFDCCID -bool yes

To enable Apple CCID driver you do:

sudo defaults write /Library/Preferences/com.apple.security.smartcard useIFDCCID -bool no

SCardControl

For my tests I used the sampe code scardcontrol included in my driver source code.

My CCID driver

$ ./scardcontrol
SCardControl sample code
V 1.4 © 2004-2010, Ludovic Rousseau [ludovic.rousseau@free.fr](mailto:ludovic.rousseau@free.fr)

THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL!
Do NOT use it unless you really know what you do.

SCardListReaders: OK
Available readers (use command line argument to select)
0: Gemalto Ezio Shield

Using reader: Gemalto Ezio Shield
Protocol: 1
SCardConnect: OK
SCardControl: OK
TLV (24): 06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 12 04 42 33 00 12
SCardControl(CM_IOCTL_GET_FEATURE_REQUEST): OK
Reader supports: FEATURE_VERIFY_PIN_DIRECT
Reader supports: FEATURE_MODIFY_PIN_DIRECT
Reader supports: FEATURE_IFD_PIN_PROPERTIES
Reader supports: FEATURE_GET_TLV_PROPERTIES

SCardControl(GET_TLV_PROPERTIES): OK
GET_TLV_PROPERTIES (59): 01 02 11 04 04 02 11 00 05 02 04 00 03 01 00 08 10 47 65 6D 43 78 30 30 2D 56 37 2E 30 34 2E 30 35 06 01 04 07 01 10 02 01 02 09 01 00 0B 02 E6 08 0C 02 C0 34 0A 04 00 00 00 00

Display all the properties:
wLcdLayout: 0x0411
Display with 4 lines of 17 columns
wLcdMaxCharacters: 0x0011
wLcdMaxLines: 0x0004
bTimeOut2: 0x00
sFirmwareID: GemCx00-V7.04.05
bMinPINSize: 0x04
bMaxPINSize: 0x10
bEntryValidationCondition: 0x02
Validation key pressed (2)
bPPDUSupport: 0x00
wIdVendor: 0x8E6
wIdProduct: 0x34C0
dwMaxAPDUDataSize: 0

Find a specific property:
wIdVendor: 0x08E6
wIdProduct: 0x34C0
PIN min size defined: 4
PIN max size defined: 16
Entry Validation Condition defined: 2

SCardControl(pin_properties_ioctl): OK
PIN PROPERTIES (4): 11 04 02 00
wLcdLayout: 0x0411
Display with 4 lines of 17 columns
bEntryValidationCondition: 2
Validation key pressed (2)
bTimeOut2: 0

Reader: Gemalto Ezio Shield (length 20 bytes)
State: 0x0054
Prot: 1
ATR (length 18 bytes): 3B 6E 00 00 80 31 80 65 B0 03 02 01 5E 83 00 00 90 00
SCardStatus: OK
Protocol: 1
SCardReconnect: OK
Select applet: 00 A4 04 00 06 A0 00 00 00 18 FF
SCardTransmit: OK
card response: 90 00

Secure verify PIN
command: 00 00 82 08 00 10 04 02 01 09 04 00 00 00 00 0D 00 00 00 00 20 00 00 08 30 30 30 30 00 00 00 00
Enter your PIN:
SCardControl: OK
card response [2 bytes]: 90 00: Success

verify PIN dump: 00 40 00 00 FF
SCardTransmit: OK
card response: 00 20 00 00 08 31 32 33 34 35 36 37 38 90 00

SCardDisconnect: OK

Apple driver

$ ./scardcontrol
SCardControl sample code
V 1.4 © 2004-2010, Ludovic Rousseau [ludovic.rousseau@free.fr](mailto:ludovic.rousseau@free.fr)

THIS PROGRAM IS NOT DESIGNED AS A TESTING TOOL!
Do NOT use it unless you really know what you do.

SCardListReaders: OK
Available readers (use command line argument to select)
0: Gemalto Ezio Shield Pro SC

Using reader: Gemalto Ezio Shield Pro SC
Protocol: 1
SCardConnect: OK
SCardControl: OK
TLV (30): 12 04 42 33 00 12 06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 13 04 42 00 00 01
SCardControl(CM_IOCTL_GET_FEATURE_REQUEST): OK
Reader supports: FEATURE_GET_TLV_PROPERTIES
Reader supports: FEATURE_VERIFY_PIN_DIRECT
Reader supports: FEATURE_MODIFY_PIN_DIRECT
Reader supports: FEATURE_IFD_PIN_PROPERTIES
Reader supports: FEATURE_CCID_ESC_COMMAND

SCardControl(GET_TLV_PROPERTIES): OK
GET_TLV_PROPERTIES (34): 01 02 11 04 03 01 00 09 01 01 0B 02 E6 08 0C 02 C0 34 0A 04 05 01 00 00 08 00 04 02 11 00 05 02 04 00

Display all the properties:
wLcdLayout: 0x0411
Display with 4 lines of 17 columns
bTimeOut2: 0x00
bPPDUSupport: 0x01
PPDU is supported over SCardControl using FEATURE_CCID_ESC_COMMAND
wIdVendor: 0x8E6
wIdProduct: 0x34C0
dwMaxAPDUDataSize: 261
sFirmwareID:
wLcdMaxCharacters: 0x0011
wLcdMaxLines: 0x0004

Find a specific property:
wIdVendor: 0x08E6
wIdProduct: 0x34C0

SCardControl(pin_properties_ioctl): OK
PIN PROPERTIES (4): 11 04 07 00
wLcdLayout: 0x0411
Display with 4 lines of 17 columns
bEntryValidationCondition: 7
Max size reached (1)
Validation key pressed (2)
Timeout occurred (4)
bTimeOut2: 0

Reader: Gemalto Ezio Shield Pro SC (length 27 bytes)
State: 0x0054
Prot: 1
ATR (length 18 bytes): 3B 6E 00 00 80 31 80 65 B0 03 02 01 5E 83 00 00 90 00
SCardStatus: OK
Protocol: 1
SCardReconnect: OK
Select applet: 00 A4 04 00 06 A0 00 00 00 18 FF
SCardTransmit: OK
card response: 90 00

Secure verify PIN
command: 00 00 82 08 00 08 04 07 01 09 04 00 00 00 00 0D 00 00 00 00 20 00 00 08 30 30 30 30 00 00 00 00
Enter your PIN:
SCardControl: OK
card response [0 bytes]::

verify PIN dump: 00 40 00 00 FF
SCardTransmit: OK
card response: 00 20 00 00 08 31 32 33 34 35 36 37 38 90 00

SCardDisconnect: OK

Diff

Here is the diff between the two outputs above:

--- libccid_pinpad      2024-02-04 15:02:41.673189176 +0100
+++ apple_pinpad        2024-02-04 15:02:18.149970763 +0100
@@ -7,54 +7,51 @@ Do NOT use it unless you really know wha

 SCardListReaders: OK
 Available readers (use command line argument to select)
-0: Gemalto Ezio Shield
+0: Gemalto Ezio Shield Pro SC

-Using reader: Gemalto Ezio Shield
+Using reader: Gemalto Ezio Shield Pro SC
  Protocol: 1
 SCardConnect: OK
 SCardControl: OK
- TLV (24): 06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 12 04 42 33 00 12
+ TLV (30): 12 04 42 33 00 12 06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 13 04 42 00 00 01
 SCardControl(CM_IOCTL_GET_FEATURE_REQUEST): OK
+Reader supports: FEATURE_GET_TLV_PROPERTIES
 Reader supports: FEATURE_VERIFY_PIN_DIRECT
 Reader supports: FEATURE_MODIFY_PIN_DIRECT
 Reader supports: FEATURE_IFD_PIN_PROPERTIES
-Reader supports: FEATURE_GET_TLV_PROPERTIES
+Reader supports: FEATURE_CCID_ESC_COMMAND

 SCardControl(GET_TLV_PROPERTIES): OK
-GET_TLV_PROPERTIES (59): 01 02 11 04 04 02 11 00 05 02 04 00 03 01 00 08 10 47 65 6D 43 78 30 30 2D 56 37 2E 30 34 2E 30 35 06 01 04 07 01 10 02 01 02 09 01 00 0B 02 E6 08 0C 02 C0 34 0A 04 00 00 00 00
+GET_TLV_PROPERTIES (34): 01 02 11 04 03 01 00 09 01 01 0B 02 E6 08 0C 02 C0 34 0A 04 05 01 00 00 08 00 04 02 11 00 05 02 04 00

 Display all the properties:
  wLcdLayout: 0x0411
   Display with 4 lines of 17 columns
- wLcdMaxCharacters: 0x0011
- wLcdMaxLines: 0x0004
  bTimeOut2: 0x00
- sFirmwareID: GemCx00-V7.04.05
- bMinPINSize: 0x04
- bMaxPINSize: 0x10
- bEntryValidationCondition: 0x02
-  Validation key pressed (2)
- bPPDUSupport: 0x00
+ bPPDUSupport: 0x01
+  PPDU is supported over SCardControl using FEATURE_CCID_ESC_COMMAND
  wIdVendor: 0x8E6
  wIdProduct: 0x34C0
- dwMaxAPDUDataSize: 0
+ dwMaxAPDUDataSize: 261
+ sFirmwareID:
+ wLcdMaxCharacters: 0x0011
+ wLcdMaxLines: 0x0004

 Find a specific property:
  wIdVendor: 0x08E6
  wIdProduct: 0x34C0
- PIN min size defined: 4
- PIN max size defined: 16
- Entry Validation Condition defined: 2

 SCardControl(pin_properties_ioctl): OK
-PIN PROPERTIES (4): 11 04 02 00
+PIN PROPERTIES (4): 11 04 07 00
  wLcdLayout: 0x0411
   Display with 4 lines of 17 columns
- bEntryValidationCondition: 2
+ bEntryValidationCondition: 7
+  Max size reached (1)
   Validation key pressed (2)
+  Timeout occurred (4)
  bTimeOut2: 0

- Reader: Gemalto Ezio Shield (length 20 bytes)
+ Reader: Gemalto Ezio Shield Pro SC (length 27 bytes)
  State: 0x0054
  Prot: 1
  ATR (length 18 bytes): 3B 6E 00 00 80 31 80 65 B0 03 02 01 5E 83 00 00 90 00
@@ -66,10 +63,10 @@ SCardTransmit: OK
  card response: 90 00

  Secure verify PIN
- command: 00 00 82 08 00 10 04 02 01 09 04 00 00 00 00 0D 00 00 00 00 20 00 00 08 30 30 30 30 00 00 00 00
+ command: 00 00 82 08 00 08 04 07 01 09 04 00 00 00 00 0D 00 00 00 00 20 00 00 08 30 30 30 30 00 00 00 00
 Enter your PIN:
 SCardControl: OK
- card response [2 bytes]: 90 00: Success
+ card response [0 bytes]::

 verify PIN dump: 00 40 00 00 FF
---

Some differences to note:

FEATURE_CCID_ESC_COMMAND

Apple driver reports it supports FEATURE_CCID_ESC_COMMAND.

According to Interoperability Specification for ICCs and Personal Computer Systems, Part 10 IFDs with Secure PIN Entry Capabilities page 27:

2.6.15 FEATURE_CCID_ESC_COMMAND

This feature can be used to retrieve the control code to send a CCID escape command (PC_to_RDR_Escape see [4]) to the reader.

The input parameter for this feature is a pointer to the abData field (see [4]) containing the specific escape command.

The output parameter is a pointer to a buffer that will contain the reader response. Note that a CCID escape command is specific to a given reader, so before issuing this command, the application has to make sure it addresses the appropriate reader.

With my driver, for security reasons, this feature is active only if enabled in the Info.plist file for ifdDriverOptions option.

bPPDUSupport

Apple driver reports bPPDUSupport: 0x01.

According to Interoperability Specification for ICCs and Personal Computer Systems, Part 10 IFDs with Secure PIN Entry Capabilities page 25:

bPPDUSupport.

  • Bit0: If set to 1, PPDU is supported over SCardControl using FEATURE_CCID_ESC_COMMAND

  • Bit1: If set to 1, PPDU is supported over SCardTransmit

My driver does not support PPDU (Pseudo APDU) because SCardControl() works fine so not need of PPDUs.

dwMaxAPDUDataSize

Apple driver reports: dwMaxAPDUDataSize: 261.

According to Interoperability Specification for ICCs and Personal Computer Systems, Part 10 IFDs with Secure PIN Entry Capabilities page 26:

dwMaxAPDUDataSize

Maximal size of data the reader and its driver can support

  • 0: short APDU only.

  • 0<X<=256: forbidden values (RFU)

  • 256 < X <= 0x10000: short and extended APDU of up to X bytes of data

  • 0x10000 < X: invalid values (RFU)

261 is a very strange value. Even more strange if you know that this reader supports short APDU only. The correct value (as correctly reported by my driver) is 0 for this reader.

sFirmwareID

Apple driver reports: sFirmwareID:.

The firmware string is empty. This is not suprising since a proprietary command is used to get the firmware release string from a Gemalto reader.

My driver reports: sFirmwareID: GemCx00-V7.04.05.

Maybe the Apple driver should not report any sFirmwareID if no data is provided.

bEntryValidationCondition

Apple driver reports: bEntryValidationCondition: 7.

7 (00000111b in binary) should be the default value. But this specific reader does only supports "Validation key pressed" but not "Max size reached" or "Timeout occurred" as wrongly indicated by the Apple driver.

My driver reports the correct value bEntryValidationCondition: 2.

PIN min/max size defined

Apple driver does NOT report PIN min and max sizes.

This can be problematic if the application does not know what values to use with a specific reader. Not all readers support the same min and max values.

Secure Verify PIN comand

The most problematic issue is that the Secure Verify PIN command (FEATURE_VERIFY_PIN_DIRECT) using the Apple driver returns:

Secure verify PIN
command: 00 00 82 08 00 08 04 07 01 09 04 00 00 00 00 0D 00 00 00 00 20 00 00 08 30 30 30 30 00 00 00 00
Enter your PIN:
SCardControl: OK
card response [0 bytes]::

The SCardControl() returns SCARD_S_SUCCESS (i.e. no error) but the PIN is not asked by the pinpad reader, and of course not submitted and verified by the card.

This command just silently fails. A pinpad reader can't be used with the Apple CCID driver.

Conclusion

You may have problems if you use the Apple driver with the SCardControl() function.

My advice is to enable my CCID driver and not use the Apple driver. It is very easy to do since both drivers are provided with macOS Sonoma (see Switch CCID driver from above).