Programmierung der Windows WinSCard-API in C

Die Microsoft WinSCard-API ermöglicht den direkten  Datenaustausch zwischen Smartcard Readern und Karten unter der Verwendung von APDUs. Die C-Funktionen der WinSCard-API sind in der Headerdatei winscard.h und die Returncodes in der Headerdatei winerror.h deklariert.

Die nachfolgende Tabelle enthält die wichtigsten WinSCard-API Funktionen. Eine detailliertere Beschreibung aller Funktionsparameter findet man in der MSDN-Library Dokumention.

Funktion

Beschreibung

 SCardEstablishContext()

Stellt eine Verbindung zum Resource Manager Context her. Die Funktion liefert einen Handle auf den Resource Manager Context.

 SCardListReaders()

Retourniert eine Liste von im System verfügbaren Smartcard Reader in Form eines Multi-C-Strings. Getrennt werden die Strings über das Null-Zeichen. Das Ende des Multi-Strings wird durch ein zusätzliches Null-Zeichen repräsentiert.

 SCardGetStatusChange()

Die Funktion blockiert solange die Programmausführung, bis sich ein definierter Kartenstatus verändert.

 SCardConnect()

Retourniert nach erfolgreicher Kartenaktivierung den Karten-Handle und stellt somit eine logische Verbindung zur Karte her.

 SCardGetAttrib()

Mit Hilfe der SCardGetAttrib() Funktion kann man eine Reihe von unterschiedlichen Reader Eigenschaften auslesen. Über einen Funktionsparameter wird die gewünschte Eigenschaft ausgewählt. ATR, Readername, Herstellername sowie diverse Kommunikationsparameter zählen zu den Eigenschaften.

 SCardControl()

Die Funktion SCardControl() dient zur Steuerung und Konfiguration der Readerhardware. Beispielsweise unterstützen einige kontaktlose PC/SC Reader das Ein- und Ausschalten des HF-Felds und das Limitieren der max. Baudrate.

 SCardTransmit()

Sendet eine Command APDU zur Karte und retourniert die Response APDU.

 SCardDisconnect()

Beendet die logische Verbindung zu einer Karte.

 SCardReleaseContext()

Schließt die Verbindung zum Resource Manager.

Alle Funktionen der Windows-API sind ausschließlich in der Programmiersprache C geschrieben. Daher kann man am einfachsten die Funktionen der Windows WinSCard-API in der Programmiersprache C/C++ aufrufen. Alle anderen Programmiersprachen wie Java, C#, Visual Basic usw. benötigen einen Wrapper. Der Wrapper agiert in diesem Fall als Schnittstelle zwischen einer Programmiersprache und der WinSCard-API.

Im Kapitel 11  werden die wichtigsten WinSCard-API Funktionen werden anhand einer Konsolenanwendung vorgestellt. Diese ist in der Programmiersprache C erstellt. Auch wenn Sie PC/SC Anwendungen in einer anderen Programmiersprache entwickeln, ist es von Vorteil, die Funktionsweise der WinSCard-API im Detail zu kennen.

icon_zip.gif Beispielprojekt: Programmierung der 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;    
}

In der Datei  main.c befindet sich das Hauptprogramm. Das Beispiel gibt die Kartenserien-nummer einer kontaktlosen Karte auf der Konsole aus. Die Kartenseriennummer wird mit dem pseudo APDU Kommando  GetData (siehe Kapitel 11.1.2.1) ermittelt. Dieses Beispiel kann man bedenkenlos mit einem kontaktbehafteten Reader testen. In diesem Fall ist die GetData Response APDU ungleich 0x9000.
 
Die Hilfsfunktion  getClessCardType()  ermittelt den Kartentyp einer kontaktlosen Speicher-karte durch einen einfachen byteweisen Vergleich des vom Reader erzeugten pseudo ATR mit der pseudo ATR einer MIFARE 1K, MIFARE 4K und MIFARE Ultralight Karte (siehe Kapitel 11.1.3.3).

Konsolenausgabe des PC/SC Beispiels