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.

Makefile:

CC=cc
CFLAGS=-pthread -I/usr/include/PCSC -c
LDFLAGS=-lpcsclite

all: main.o main

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

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

clean:
	rm -rf *.o readSmartCard

main.c:

#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;
	SCARDCONTEXT hContext;
	SCARDHANDLE hCard;
	DWORD dwReaders, dwActiveProtocol, dwRecvLength;
	LPTSTR mszReaders;
	SCARD_IO_REQUEST pioSendPci;
	BYTE pbRecvBuffer[266];
	unsigned int i;

	fprintf(stderr, "Smart Card reader - terciofilho - hashtips.wordpress.com\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]);
	}
	else
	{
		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);

	dwReaders = SCARD_AUTOALLOCATE;
	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)

	switch(dwActiveProtocol)
	{
		case SCARD_PROTOCOL_T0:
			pioSendPci = *SCARD_PCI_T0;
			break;

		case SCARD_PROTOCOL_T1:
			pioSendPci = *SCARD_PCI_T1;
			break;
	}
	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.

Advertisements

3 thoughts on “How to read a SLE4442/32 SmartCard using PCSC

  1. Pingback: SLE4442 smart card Bus Pirate GUI | Yaehob (Yet Another E-Hobbyist) blog…

  2. Hello guys, what changes i should do to make it work into windows?
    i would use devc++
    I had bought the same cardtype SLE4442 for a small project. But i don’t know C, i just know a little C++?
    it is possible to translate it into C++?
    Thanks for any support.

    ps. after copying the codes, the compiler give this error:

    line row file message
    6 5 C:\Users\Anwender\Desktop\chipcard\main.c [Error] expected identifier or \'(\’ before ‘if’
    12 5 C:\Users\Anwender\Desktop\chipcard\main.c [Error] expected identifier or \'(\’ before ‘if’
    28 C:\Users\Anwender\Desktop\chipcard\Makefile.win recipe for target ‘main.o\’ failed

    • Hi! Probably a typo, check if lines 5 to 14 have a slash(\) in the end of line.
      Or you can replace lines 5 to 15 by:


      #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; }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s