Basic Smart Card Console Application

  • Posted on: 1 June 2014
  • By: siteadm

I had to run some tests on some smart cards I received recently in Debian. I did some research to find a very simple, very basic command line code, compilable and runnable in Debian, which will run HEX commands in smart card and show the results again in hex and .
So I wasn't able to find such a code and I decided to write my own. From now on, you can use it too:
Sample.c

#ifdef WIN32
#include <stdio.h>
#include <stdlib.h>
#include <winscard.h>
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#endif

SCARDCONTEXT hCard;
LPTSTR strReaders;

#define _base(x) ((x >= '0' && x <= '9') ? '0' : \
         (x >= 'a' && x <= 'f') ? 'a' - 10 : \
         (x >= 'A' && x <= 'F') ? 'A' - 10 : \
            '\255')
#define HEXOF(x) (x - _base(x))

void DisplayErrorAndTerminate(char *srcFunc, int retval)
{
	printf("Error at: %s - Explanation: %s\n", srcFunc, pcsc_stringify_error(retval));
	exit(1);
}

void QuitApp()
{
	int retval;

	retval = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
	retval = SCardFreeMemory(hCard, strReaders);
	retval = SCardReleaseContext(hCard);
	exit(1);
}


int main(int argc, char *argv[])
{
	
	DWORD dwReaders, dwrecvlen, dwActiveProtocol, dwReaderLen, dwAtrLen, dwProt, dwState;
	SCARD_IO_REQUEST pCardSendIO;
	BYTE bAtr[MAX_ATR_SIZE] = "";
	char strReader[MAX_READERNAME] = "";

	LONG retval;
	int i;
	BYTE recvbuf[260];

	char uinput[260];
	int counter=0;
	char *p;
	unsigned char *output;


	retval = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hCard);
	if (retval != SCARD_S_SUCCESS) 
		DisplayErrorAndTerminate("SCardEstablishContext", retval);

	dwReaders = SCARD_AUTOALLOCATE;
	retval = SCardListReaders(hCard, NULL, (LPSTR)&strReaders, &dwReaders);
	if (retval != SCARD_S_SUCCESS) DisplayErrorAndTerminate("SCardListReaders", retval);

	retval = SCardConnect(hCard, strReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
	if (retval != SCARD_S_SUCCESS) DisplayErrorAndTerminate("SCardConnect", retval);

	dwAtrLen = sizeof(bAtr);
	dwReaderLen = sizeof(strReader);
	retval = SCardStatus(hCard, strReader, &dwReaderLen, &dwState, &dwProt, bAtr, &dwAtrLen);
	if (retval != SCARD_S_SUCCESS) DisplayErrorAndTerminate("SCardStatus", retval);

	printf("Reader name: %s\n", strReader);
	printf("ATR: ");
	for (i=0; i < dwAtrLen; i++)
		printf(" %02X", bAtr[i]);
	printf("\n");

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

		case SCARD_PROTOCOL_T1:
			pCardSendIO = *SCARD_PCI_T1;
			break;
	}

	printf("\nType QUIT to exit\n");
	while (1)
	{
		printf("\nEnter command hex with spaces: ");
		fgets(uinput, sizeof(uinput), stdin);
		strtok(uinput, "\n");

		if (strcmp(uinput, "QUIT") == 0) QuitApp();

		output = malloc(sizeof(uinput) >> 1);
		counter=-1;
		
		for (p = uinput; p && *p; p+=3 ) {
			counter++;
			output[counter] = ((HEXOF(*p)) << 4) + HEXOF(*(p+1));
		}
		counter++;

		dwrecvlen = sizeof(recvbuf);
		retval = SCardTransmit(hCard, &pCardSendIO, output, (counter * sizeof(unsigned char)), NULL, recvbuf, &dwrecvlen);
		if (retval != SCARD_S_SUCCESS) DisplayErrorAndTerminate("SCardTransmit", retval);

		printf("Response: ");
		for(i=0; i < dwrecvlen; i++)
	  		printf("%02X ", recvbuf[i]);
		printf("\n");

	}
	
	return 0;
}






Makefile:

# Linux
PCSC_CFLAGS := $(shell pkg-config --cflags libpcsclite)
LDFLAGS := $(shell pkg-config --libs libpcsclite)

CFLAGS += $(PCSC_CFLAGS)

sample: 
	gcc -o $@ $^ $(CFLAGS) $(LDFLAGS) sample.c

clean:
	rm -f sample




Simply save both files in a folder, run make, then you can run it just by typing ./sample in terminal.


In windows you'll need to link to winscard too, so you can just add #pragma comment(lib, "winscard.lib") below #includes. To be honest, I never tried it in Windows, but seems like it should work.


Usage is easy, just type your smart card commands in hex like "AA BB CC DD" (should have spaces) and type "QUIT" to gracefully close smart card handles and terminate the app, it's better to type QUIT to terminate app instead of CTRL+C or CTRL+Z to suspend or terminate process.


Feel free to contact me about this code

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
CAPTCHA
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.
Image CAPTCHA
Enter the characters shown in the image.