How to read a SLE4442/32 SmartCard using PCSC

Recently, I had to read bytes from a SLE4442 SmartCard in a Linux server(Ubuntu, as usual).

There are some alternatives to read/write these SmartCards, the most widespread is PC/SC-lite. In the PC/SC tools there is a valuable program called “scriptor”, which will allow you to send commands from STDIN to the card reader and get direct feedback from your card. This is useful when you are debugging, but in production I needed a small executable(Scriptor is a perl script) to run in the ramdisk(initrd) and print the card’s content to STDOUT.

Here is a small C program I created that will connect to the card reader, send two commands(Detailed below) and print the card’s content to STDOUT.
Commands(Hex notation):

  • Select Card Type, in this case SLE4432 or SLE4442 or SLE5532 or SLE5542.
    • Command: “FF A4 00 00 01 06”, this command powers down and powers up the selected card and performs a card reset.
  • Read card content
    • Command: “FF B0 00 XX YY”, this command reads the card memory at address XX, YY bytes long.

You can provide 2 parameters to the program, the first address to be read, and how many bytes. eg:

# Will read 128 bytes starting at the 32th byte.
$ ./smartCardRead 20 80
# Will read 16 bytes starting at the first byte.
$ ./smartCardRead 00 10

By default, it will read from the first address, 256 bytes.

Before trying to compile the program below, you need to install some packages:

apt-get install build-essential pcscd pcsc-tools libpcsclite1 libpcsclite-dev
  • build-essential – Basic packages needed to compile a program
  • pcscd – Daemon that will allow libpcsclite connect to card readers
  • pcsc-tools – Tools, like scriptor, pcsc_scan, etc.
  • libpcsclite1 – Library PC/SC-lite
  • libpcsclite-dev – Library headers files

After installing these packages, just create the two files below and run make.


CFLAGS=-pthread -I/usr/include/PCSC -c

all: main.o main

main: main.o
	$(CC) main.o $(LDFLAGS) -o readSmartCard

main.o: main.c
	$(CC) $(CFLAGS) main.c

	rm -rf *.o readSmartCard


#include <stdio.h>
#include <stdlib.h>
#include <winscard.h>

#define CHECK(f, rv) \
	if (SCARD_S_SUCCESS != rv) \
	{ \
		fprintf(stderr, f ": %s\n", pcsc_stringify_error(rv)); \
		return -1; \
#define CHECK_RESPONSE(buffer, bufferLength) \
	if(buffer[bufferLength-2] != 0x90 || buffer[bufferLength-1] != 0x00) { \
		fprintf(stderr, "Invalid response!\n"); \
		return -2; \

int main(int argc, char *argv[]) {
	LONG rv;
	DWORD dwReaders, dwActiveProtocol, dwRecvLength;
	LPTSTR mszReaders;
	BYTE pbRecvBuffer[266];
	unsigned int i;

	fprintf(stderr, "Smart Card reader - terciofilho -\n");

	BYTE cmdDefineCardType[] = { 0xFF, 0xA4, 0x00, 0x00, 0x01, 0x06 };
	BYTE cmdReadCard[] = { 0xFF, 0xB0, 0x00, 0x20, 0xC0 };

	if(argc != 3)
		fprintf(stderr, "Usage: %s FIRST_ADDRESS READ_LENGTH\nNo parameters provided, default values:\nFIRST_ADDRESS = 0x%X\nREAD_LENGTH = 0x%X\n", argv[0], cmdReadCard[3], cmdReadCard[4]);
		if(strtol(argv[2], NULL, 16) > 256)
			fprintf(stderr, "Invalid READ_LENGTH. Must be < 256.\n");
			return -3;
		cmdReadCard[3] = strtol(argv[1], NULL, 16);
		cmdReadCard[4] = strtol(argv[2], NULL, 16);
		fprintf(stderr, "FIRST_ADDRESS = 0x%02x\nREAD_LENGTH = 0x%02x\n", cmdReadCard[3], cmdReadCard[4]);

	rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
	CHECK("SCardEstablishContext", rv);

	rv = SCardListReaders(hContext, NULL, (LPTSTR)&mszReaders, &dwReaders);
	CHECK("SCardListReaders", rv)
	fprintf(stderr, "Reader name: %s\n", mszReaders);

	rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
	CHECK("SCardConnect", rv)

			pioSendPci = *SCARD_PCI_T0;

			pioSendPci = *SCARD_PCI_T1;
	dwRecvLength = sizeof(pbRecvBuffer);

	rv = SCardTransmit(hCard, &pioSendPci, cmdDefineCardType, sizeof(cmdDefineCardType), NULL, pbRecvBuffer, &dwRecvLength);
	CHECK("SCardTransmit", rv)
	CHECK_RESPONSE(pbRecvBuffer, dwRecvLength);

	dwRecvLength = sizeof(pbRecvBuffer);
	rv = SCardTransmit(hCard, &pioSendPci, cmdReadCard, sizeof(cmdReadCard), NULL, pbRecvBuffer, &dwRecvLength);
	CHECK("SCardTransmit", rv)
	CHECK_RESPONSE(pbRecvBuffer, dwRecvLength);

	for(i=0; i<dwRecvLength-2; i++)
		printf("%c", pbRecvBuffer[i]);

	rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
	CHECK("SCardDisconnect", rv);

	rv = SCardFreeMemory(hContext, mszReaders);
	CHECK("SCardFreeMemory", rv);

	rv = SCardReleaseContext(hContext);
	CHECK("SCardReleaseContext", rv);

There is a manual out there, that is VERY helpful when sending commands to these cards, PMA-ACR38x(CCID)-6.02.

DISCLAIMER: I cannot guarantee that this code is bug free or will work in your setup. I’m not a C guru, I didn’t check all possible failure points.