For macOS Developer

The reader using PC/SC Lite in macOS platform, if you are using the reader in Linux platform, you may need check your system installed latest CCID driver.

If you confirm you have install the CCID driver, make sure your pcscd service has running, and you also install the pcsclite-dev.

Languages

C to get reader USB iSerialNumber

C for PC/SC API


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


typedef unsigned int uint32_t;
#define PANIC 0
#define DONT_PANIC 1


#define SCARD_ATTR_ATR_STRING 590595

void test_rv(LONG rv, SCARDCONTEXT hContext, int dont_panic);
void test_rv(LONG rv, SCARDCONTEXT hContext, int dont_panic)
{
    if (rv != SCARD_S_SUCCESS)
    {
        if (dont_panic)
            printf( "%s (don't panic)\n" , pcsc_stringify_error(rv));
        else
        {
            printf( "%s\n" , pcsc_stringify_error(rv));
            SCardReleaseContext(hContext);
        }
    }
    else
        puts(pcsc_stringify_error(rv));
}

int main(int argc, char **argv)
{
    SCARDHANDLE hCard;
    SCARDCONTEXT hContext;
    SCARD_READERSTATE_A rgReaderStates[1];
    DWORD dwReaderLen, dwState, dwProt, dwAtrLen;
    DWORD dwPref, dwReaders = 0;
    char *pcReaders, *mszReaders;
    unsigned char pbAtr[MAX_ATR_SIZE];
    char *mszGroups;
    DWORD dwGroups = 0;
    LONG rv;
    DWORD i;
    int p, iReader;
    int iList[16];
    SCARD_IO_REQUEST pioRecvPci;
    SCARD_IO_REQUEST pioSendPci;
    unsigned char bSendBuffer[MAX_BUFFER_SIZE];
    unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
    DWORD send_length, length;

    printf("\nMUSCLE PC/SC Lite unitary test Program\n\n");


    printf("Testing SCardEstablishContext\t: ");
    rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
    test_rv(rv, hContext, PANIC);

    printf("Testing SCardGetStatusChange \n");
    printf("Please insert a working reader\t: ");
    fflush(stdout);
    rv = SCardGetStatusChange(hContext, INFINITE, 0, 0);
    test_rv(rv, hContext, PANIC);

    printf("Testing SCardListReaderGroups\t: ");
    rv = SCardListReaderGroups(hContext, 0, &dwGroups);
    test_rv(rv, hContext, PANIC);

    printf("Testing SCardListReaderGroups\t: ");
    mszGroups = calloc(dwGroups, sizeof(char));
    rv = SCardListReaderGroups(hContext, mszGroups, &dwGroups);
    test_rv(rv, hContext, PANIC);

    /*
     * Have to understand the multi-string here
     */
    p = 0;
    for (i = 0; i+1 < dwGroups; i++)
    {
        ++p;
        printf( "Group %02d: %s\n" , p, &mszGroups[i]);
        iList[p] = i;
        while (mszGroups[++i] != 0) ;
    }

wait_for_card_again:
    printf("Testing SCardListReaders\t: ");

    mszGroups = NULL;
    rv = SCardListReaders(hContext, mszGroups, 0, &dwReaders);
    test_rv(rv, hContext, PANIC);

    printf("Testing SCardListReaders\t: ");
    mszReaders = calloc(dwReaders, sizeof(char));
    rv = SCardListReaders(hContext, mszGroups, mszReaders, &dwReaders);
    test_rv(rv, hContext, PANIC);

    /*
     * Have to understand the multi-string here
     */
    p = 0;
    for (i = 0; i+1 < dwReaders; i++)
    {
        ++p;
        printf( "Reader %02d: %s\n" , p, &mszReaders[i]);
        iList[p] = i;
        while (mszReaders[++i] != 0) ;
    }

    if (p > 1)
        do
        {
            char input[80];

            printf("Enter the reader number\t\t: ");
            fgets(input, sizeof(input), stdin);
            sscanf(input, "%d", &iReader);

            if (iReader > p || iReader <= 0)
                printf("Invalid Value - try again\n");
        }
    while (iReader > p || iReader <= 0);
    else
        iReader = 1;

    rgReaderStates[0].szReader = &mszReaders[iList[iReader]];
    rgReaderStates[0].dwCurrentState = SCARD_STATE_EMPTY;

    printf("Waiting for card insertion\t: ");
    fflush(stdout);
    rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
    test_rv(rv, hContext, PANIC);
    if (SCARD_STATE_EMPTY == rgReaderStates[0].dwEventState)
    {
        printf("\nA reader has been connected/disconnected\n");
        goto wait_for_card_again;
    }

    printf("Testing SCardConnect\t\t: ");
    rv = SCardConnect(hContext, &mszReaders[iList[iReader]],
                      SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1,
                      &hCard, &dwPref);
    test_rv(rv, hContext, PANIC);

    switch(dwPref)
    {
        case SCARD_PROTOCOL_T0:
            pioSendPci = *SCARD_PCI_T0;
            break;
        case SCARD_PROTOCOL_T1:
            pioSendPci = *SCARD_PCI_T1;
            break;
        default:
            printf("Unknown protocol\n");
            return -1;
    }

    /* APDU select file */
    printf("Select file:");
    send_length = 7;
    memcpy(bSendBuffer, "\x00\xA4\x00\x00\x02\x3F\x00", send_length);
    for (i=0; i<send_length; i++)
        printf(" %02X", bSendBuffer[i]);
    printf("\n");
    length = sizeof(bRecvBuffer);

    printf("Testing SCardTransmit\t\t: ");
    rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
                       &pioRecvPci, bRecvBuffer, &length);
    printf("%s\n", pcsc_stringify_error(rv));
    printf(" card response:" );
    for (i=0; i<length; i++)
        printf(" %02X", bRecvBuffer[i]);
    printf("\n" );

    /* APDU ramdom */
    printf("Get 8 bytes Ramdom Number:");
    send_length = 5;
    memcpy(bSendBuffer, "\x00\x84\x00\x00\x08", send_length);
    for (i=0; i<send_length; i++)
        printf(" %02X", bSendBuffer[i]);
    printf("\n");
    length = sizeof(bRecvBuffer);

    printf("Testing SCardTransmit\t\t: ");
    rv = SCardTransmit(hCard, &pioSendPci, bSendBuffer, send_length,
                       &pioRecvPci, bRecvBuffer, &length);
    printf("%s\n", pcsc_stringify_error(rv));
    printf(" card response:" );
    for (i=0; i<length; i++)
        printf(" %02X", bRecvBuffer[i]);
    printf("\n" );



    printf("Testing SCardGetAttrib\t\t: ");
    rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, NULL, &dwAtrLen);
    test_rv(rv, hContext, DONT_PANIC);
    if (rv == SCARD_S_SUCCESS)
        printf("SCARD_ATTR_ATR_STRING length: "  "%ld\n" , dwAtrLen);

    printf("Testing SCardGetAttrib\t\t: ");
    dwAtrLen = sizeof(pbAtr);
    rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAtr, &dwAtrLen);
    test_rv(rv, hContext, DONT_PANIC);
    if (rv == SCARD_S_SUCCESS)
    {
        printf("SCARD_ATTR_ATR_STRING: " );
        for (i = 0; i < dwAtrLen; i++)
            printf("%02X ", pbAtr[i]);
        printf("\n" );
    }


    printf("Testing SCardStatus\t\t: ");

    dwReaderLen = 100;
    pcReaders   = malloc(sizeof(char) * 100);
    dwAtrLen    = MAX_ATR_SIZE;

    rv = SCardStatus(hCard, pcReaders, &dwReaderLen, &dwState, &dwProt,
                     pbAtr, &dwAtrLen);
    test_rv(rv, hContext, PANIC);

    printf("Current Reader Name\t\t: "  "%s\n" , pcReaders);
    printf("Current Reader State\t\t: "  "0x%.4x\n" , dwState);
    printf("Current Reader Protocol\t\t: T="  "%u\n" , dwProt - 1);
    printf("Current Reader ATR Size\t\t: "  "%u"  " bytes\n",
           dwAtrLen);
    printf("Current Reader ATR Value\t: " );

    for (i = 0; i < dwAtrLen; i++)
    {
        printf("%02X ", pbAtr[i]);
    }
    printf( "\n");

    if (rv != SCARD_S_SUCCESS)
    {
        SCardDisconnect(hCard, SCARD_RESET_CARD);
        SCardReleaseContext(hContext);
    }


    //sleep(1);
    printf("Testing SCardReconnect\t\t: ");
    rv = SCardReconnect(hCard, SCARD_SHARE_SHARED,
                        SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_UNPOWER_CARD, &dwPref);
    test_rv(rv, hContext, PANIC);

    printf("Testing SCardDisconnect\t\t: ");
    rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
    test_rv(rv, hContext, PANIC);

    printf("Testing SCardReleaseContext\t: ");
    rv = SCardReleaseContext(hContext);
    test_rv(rv, hContext, PANIC);

    printf("\n");
    printf("PC/SC Test Completed Successfully !\n");

    return 0;
}

GO

package main
import(
    "fmt"
    "github.com/ebfe/scard"
)
func main() {
    // Establish a PC/SC context
    context,
    err: = scard.EstablishContext()
    if err != nil {
        fmt.Println("Error EstablishContext:", err)
        return
    }
    // Release the PC/SC context (when needed)
    defer context.Release()
    // List available readers
    readers,
    err: = context.ListReaders()
    if err != nil {
        fmt.Println("Error ListReaders:", err)
        return
    }
    // Use the first reader
    reader: = readers[0]
    fmt.Println("Using reader:", reader)
    // Connect to the card
    card,
    err: = context.Connect(reader, scard.ShareShared, scard.ProtocolAny)
    if err != nil {
        fmt.Println("Error Connect:", err)
        return
    }
    // Disconnect (when needed)
    defer card.Disconnect(scard.LeaveCard)
    // Send select APDU
    var cmd_select = [] byte {
        0x00,
        0xa4,
        0x04,
        0x00,
        0x0A,
        0xA0,
        0x00,
        0x00,
        0x00,
        0x62,
        0x03,
        0x01,
        0x0C,
        0x06,
        0x01
    }
    rsp,
    err: = card.Transmit(cmd_select)
    if err != nil {
        fmt.Println("Error Transmit:", err)
        return
    }
    fmt.Println(rsp)
    // Send command APDU
    var cmd_command = [] byte { 0x00, 0x00, 0x00, 0x00 }
    rsp,
    err = card.Transmit(cmd_command)
    if err != nil {
        fmt.Println("Error Transmit:", err)
        return
    }
    fmt.Println(rsp)
    for i: = 0;i < len(rsp)‐ 2;i++{
        fmt.Printf("%c", rsp[i])
    }
    fmt.Println()
}

Objective-C

#import <CryptoTokenKit/CryptoTokenKit.h>
int main(int argc, const char * argv[]) {
    TKSmartCardSlotManager * mngr;
    mngr = [TKSmartCardSlotManager defaultManager];

    // Use the first reader/slot found
    NSString * slotName = (NSString * ) mngr.slotNames[0];
    NSLog(@ "slotName: %@", slotName);

    // connect to the slot
    [mngr getSlotWithName: slotName reply: ^(TKSmartCardSlot * slot) {
        // connect to the card
        TKSmartCard * card = [slot makeSmartCard];
        if (card) {
            // begin a session
            [card beginSessionWithReply: ^(BOOL success, NSError * error) {
                if (success) {
                    // send 1st APDU
                    uint8_t aid[] = {
                        0xA0,
                        0x00,
                        0x00,
                        0x00,
                        0x62,
                        0x03,
                        0x01,
                        0x0C,
                        0x06,
                        0x01
                    };
                    NSData * data = [NSData dataWithBytes: aid length: sizeof aid];
                    [card sendIns: 0xA4 p1: 0x04 p2: 0x00 data: data le: nil reply: ^ (NSData * replyData, UInt16 sw, NSError * error) {
                        if (error) {
                            NSLog(@ "sendIns error: %@", error);
                        } else {
                            NSLog(@ "Response: %@ 0x%04X", replyData, sw);
                            // send 2nd APDU
                            NSData * data = [NSData dataWithBytes: nil length: 0];
                            [card sendIns: 0x00 p1: 0x00 p2: 0x00 data: data le: @200 reply: ^ (NSData * replyData, UInt16 sw, NSError * error) {
                                    if (error) {
                                        NSLog(@ "sendIns error: %@", error);
                                    } else {
                                        NSLog(@ "Response: %@ 0x%04X", replyData, sw);
                                        NSString * newString = [[NSString alloc] initWithData: replyData encoding: NSASCIIStringEncoding];
                                        NSLog(@ "%@", newString);
                                    }

                            }];
                        }

                    }];
                } else {
                    NSLog(@ "Session error: %@", error);
                }
            }];
        } else {
            NSLog(@ "No card found");
        }
    }];
    // wait for the asynchronous blocks to finish
    sleep(1);
    return 0;
}

swift

import CryptoTokenKit;
let mngr = TKSmartCardSlotManager.defaultManager()

// Use the first reader/slot found
let slotName = mngr!.slotNames[0]
print("slotName:", slotName)

// connect to the slot
mngr?.getSlotWithName(slotName, reply: { (slot: TKSmartCardSlot? ) in
    // connect to the card
    let card = slot?.makeSmartCard()
    if (card != nil) {
        // begin a session
        card?.beginSessionWithReply({ (success: Bool, error: NSError?) in
            if (success) {
                // send 1st APDU
                let aid: [UInt8] = [0xA0, 0x00, 0x00, 0x00, 0x62, 0x03, 0x01, 0x0C, 0x06, 0x01]
                let data = NSData(bytes: aid, length: aid.count)
                card?.sendIns(0xA4, p1: 0x04, p2: 0x00, data: data, le: 0, reply: { (data: NSData?, sw : UInt16, error: NSError? ) in
                    if (error != nil) {
                        print("sendIns error:", error!)
                    } else {
                        print("Response:", data!, String(sw, radix: 16))
                        // send 2nd APDU
                        let data = NSData(bytes: nil, length: 0)
                        card?.sendIns(0x0, p1: 0x00, p2: 0x00, data: data, le: 200, reply: { (data: NSData?, sw : UInt16, error: NSError? ) in
                            if (error != nil) {
                                print("sendIns error:", error!)
                            } else {
                                print("Response:", data!, String(sw, radix: 16))
                                let newString = NSString(bytes: data!.bytes, length: data!.length, encoding: NSASCIIStringEncoding)
                                print(newString!)
                            }
                        })
                    }
                })
            } else {
                print("Session error:", error)
            }
        })
    } else {
        print("No card found")
    }
})
// wait for the asynchronous blocks to finish
sleep(1)