Programming the WinSCard API in "C"

The WinSCard API makes direct exchange of data between readers and cards possible by using APDUs. The WinSCard API’s C functions are declared in the header file, winscard.h, and the return codes are declared in winerror.h.

The table below lists the main WinSCard API functions. A detailed description of all function parameters is available in the MSDN Library Documentation.

Function

Description

 SCardEstablishContext()

Sets up a connection to and returns the handle to the Resource Manager context.

 SCardListReaders()

Returns a list of smartcard readers available on the system, in the form of a C multi-string. Individual strings are separated by the null character (0x00). The end of the multi-string is represented by an additional null character.

 SCardGetStatusChange()

Blocks program execution until a change in card status.

 SCardConnect()

After successful card activation, returns a card handle, thus creating a logical connection to the card.

 SCardGetAttrib()

Returns a range of different reader properties. The desired property is selected using a function parameter. The ATR, the reader’s name, the manufacturer name and various communication parameters are among the available properties.

 SCardControl()

Used to control and configure the reader hardware. For example, some PC/SC readers support the ability to turn the RF field on and off and limit the maximum Baud rate.

 SCardTransmit()

Sends a command APDU to the card and returns the response APDU.

 SCardDisconnect()

Closes the logical connection to the card.

 SCardReleaseContext()

Closes the connection to the resource manager.

The Windows API functions are written entirely in the C programming language. In this way, one may simple call the WinSCard API from C / C + +. All other programming languages, such us Java, C #, Visual Basic, require a wrapper. The wrapper in this case acts as an interface between a programming language and the WinSCard API.

In Chapter 11, the main WinSCard API functions are demonstrated using a console application. This is written in the C programming language. Even if you are developing PC / SC applications in other programming languages, it is advantageous to know the WinSCard API functions in detail.

icon_zip.gif Example: Programming the WinSCard-API in C


#include <conio.h>
#include <stdio.h>
#include "pcsc.h"
#include "util.h"
#include "clessCardType.h"
    
int main(int argc, char* argv[])
{
    // Get Data: CLA = 0xFF, INS = 0xCA, P1 = 0x00, P2 = 0x00, Le = 0x00
    BYTE baCmdApduGetData[] = { 0xFF, 0xCA, 0x00, 0x00, 0x00};

    BYTE baResponseApdu[300];    
    DWORD lResponseApduLen = 0;

    BYTE atr[40];
    INT     atrLength;
    LONG lRetValue;

    system("cls");
    printf("PCSC API Example - Read Card Serial Number (UID)...\n\n");
    
    lRetValue = PCSC_Connect(NULL );
    PCSC_EXIT_ON_ERROR(lRetValue);
    
    lRetValue = PCSC_WaitForCardPresent();
    PCSC_EXIT_ON_ERROR(lRetValue);

    lRetValue = PCSC_ActivateCard();
    PCSC_EXIT_ON_ERROR(lRetValue);
    
    lRetValue = PCSC_GetAtrString(atr, &atrLength);
    PCSC_EXIT_ON_ERROR(lRetValue);

    // Send pseudo APDU to retrieve the card serical number (UID)
    PCSC_Exchange(baCmdApduGetData,(DWORD)sizeof(baCmdApduGetData),
                  baResponseApdu, &lResponseApduLen);
    PCSC_EXIT_ON_ERROR(lRetValue);
    
    // Verify if status word SW1SW2 is equal 0x9000.
    if( baResponseApdu[lResponseApduLen - 2] == 0x90 &&
        baResponseApdu[lResponseApduLen - 1] == 0x00)
    {
        // Contactless card detected.
        // Retrieve the card serical number (UID) form the response APDU.
        printHexString("Card Serial Number (UID): 0x", 
                             baResponseApdu, lResponseApduLen - 2);

        if( getClessCardType(atr) == Mifare1K)
        {
            printf("Card Type: MIFARE Classic 1k");
        }
        else if( getClessCardType(atr) == Mifare4K)
        {
            printf("Card Type: MIFARE Classic 4k");
        }
        else if( getClessCardType(atr) == MifareUL)
        {
            printf("Card Type: MIFARE Ultralight");
        }
    }

    //lRetValue = PCSC_WaitForCardRemoval();

    PCSC_Disconnect();
    
    printf("\n");
    getchar();
    return 0;    
}

The main program is shown in the main.c. The example outputs a contactless card’s serial number to the console. The card’s serial number is retrieved using the GetData pseudo-APDU command (see Section 11.1.2.1). This example can safely tried with a contact-type reader. In this case, the GetData response APDU is different to 0x9000.

The getClessCardType() auxiliary function gets the card type of a contactless memory card by doing simple byte-wise comparison of the reader generated pseudo-ATR with the known pseudo-ATRs of MIFARE 1K, MIFARE 4K and MIFARE Ultralight cards (see section 11.1.3.3).

Konsolenausgabe des PC/SC Beispiels