macOS Sonoma bug: SCardControl() returns SCARD_E_NOT_TRANSACTED

This is part of the series: "macOS Sonoma and smart cards: known bugs".

SCardControl() fails and returns SCARD_E_NOT_TRANSACTED (i.e. 0x80100016).

See also

I reported this bug as FB12779458 "SCardControl() fails on Sonoma beta 4 and returns SCARD_E_NOT_TRANSACTED (0x80100016)".

Update February 2024: The issue FB12779458 is fixed in macOS Sonoma 14.3.

Sample code

If you use the sample code:

2023_09_macOS_Sonoma_bug_SCardControl.c (Source)

//
//  main.c
//  scardcontrol
//
//  Created by Ludovic Rousseau on 28/07/2023.
//

#include <stdio.h>
#include <stdlib.h>
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>

#define SCARD_CTL_CODE(code) (0x42000000 + (code))
#define CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400)
#define PCSC_ERROR_EXIT(rv, text) \
if (rv != SCARD_S_SUCCESS) \
{ \
        printf(text ": %s (0x%8X)\n", pcsc_stringify_error(rv), rv); \
        goto end; \
} \
else \
        printf(text ": OK\n");

int main(int argc, const char * argv[]) {
        LONG rv;
        SCARDCONTEXT hContext;
        DWORD dwReaders;
        LPSTR mszReaders = NULL;
        SCARDHANDLE hCard;
        unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
        DWORD length;
        DWORD dwActiveProtocol;

        rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
        if (rv != SCARD_S_SUCCESS)
        {
                printf("SCardEstablishContext: Cannot Connect to Resource Manager %s\n", pcsc_stringify_error(rv));
                return 1;
        }

        /* Retrieve the available readers list */
        rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
        PCSC_ERROR_EXIT(rv, "SCardListReaders")

        mszReaders = malloc(sizeof(char)*dwReaders);
        if (mszReaders == NULL)
        {
                printf("malloc: not enough memory\n");
                goto end;
        }

        rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
        if (rv != SCARD_S_SUCCESS)
                printf("SCardListReader: %8X\n", rv);

        /* connect to a reader (even without a card) */
        dwActiveProtocol = -1;
        printf("Using reader: %s\n", mszReaders);
        rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_DIRECT,
                SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
        PCSC_ERROR_EXIT(rv, "SCardConnect")

        /* get features */
        rv = SCardControl(hCard, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0,
                bRecvBuffer, sizeof(bRecvBuffer), &length);
        PCSC_ERROR_EXIT(rv, "SCardControl")

        printf("Received buffer (%d bytes)\n", length);
        for (int i=0; i<length; i++)
                printf("%02X ", bRecvBuffer[i]);
        printf("\n");

        /* disconnect */
        rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
        PCSC_ERROR_EXIT(rv, "SCardDisconnect")

end:
        /* We try to leave things as clean as possible */
        rv = SCardReleaseContext(hContext);
        if (rv != SCARD_S_SUCCESS)
                printf("SCardReleaseContext: %s (0x%8X)\n", pcsc_stringify_error(rv),
                        rv);

        /* free allocated memory */
        if (mszReaders)
                free(mszReaders);

        return 0;
}

you will get:

 SCardListReaders: OK
 Using reader: Gemplus USB GemPCPinpad SmartCard Reader
 SCardConnect: OK
 SCardControl: Transaction failed. (0x80100016)
 Program ended with exit code: 0

Instead of the expected output (I get it on macOS Ventura 13.5):

 SCardListReaders: OK
 Using reader: Gemalto USB GemPCPinpad SmartCard Reader
 SCardConnect: OK
 SCardControl: OK
 Received buffer (24 bytes)
 06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 12 04 42 33 00 12
 SCardDisconnect: OK
 Program ended with exit code: 0

Why is it important

This bug is important because if SCardControl() can't be used then you can't use the secure verify command of a pinpad reader for example (i.e. enter the PIN code on the pinpad keyboard and not on the PC keyboard).

Other commands are using SCardControl(). They are documented in PC/SC specification version 2 part 10 "Interoperability Specification for ICCs and Personal Computer Systems Part 10 IFDs with Secure PIN Entry Capabilities" from the PC/SC workgroup.

See List of SCardControl() commands supported by the CCID driver.

  • GET_FEATURE_REQUEST

  • secure PIN verify (FEATURE_VERIFY_PIN_DIRECT)

  • modify PIN entry (FEATURE_MODIFY_PIN_DIRECT)

  • reader PIN properties (FEATURE_IFD_PIN_PROPERTIES)

  • Multifunctional Card Terminal reader direct (FEATURE_MCT_READER_DIRECT)

  • retrieve reader properties in TLV form (FEATURE_GET_TLV_PROPERTIES)

Know workaround

If I install a new CCID driver (my CCID driver 1.5.2 for example) then the same sample code works on Sonoma and I get the expected results.

SCardListReaders: OK
Using reader: Gemalto USB GemPCPinpad SmartCard Reader
SCardConnect: OK
SCardControl: OK
Received buffer (24 bytes)
06 04 42 33 00 06 07 04 42 33 00 07 0A 04 42 33 00 0A 12 04 42 33 00 12
SCardDisconnect: OK
Program ended with exit code: 0

It looks like the problem is with the CCID driver provided by Apple and not in the macOS PC/SC or resource manager layer.

If you need a customer driver to solve this problem please contact me.

[UPDATE November 2023]

This problem is caused by the Apple CCID driver included in Sonoma. See Apple's own CCID driver in Sonoma.

An easy way to fix the problem is to upgrade to Sonoma 14.1, or to enable my CCID driver (also provided by Apple in Sonoma) by doing:

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

[UPDATE February 2024]

Apple has worked on SCardControl() support. The issue FB12779458 is fixed in macOS Sonoma 14.3.