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

Send SMS using a USB Modem and Ubuntu 12.04

I developed a Java ERP system for a customer and he asked me if the system could send SMS messages. My first thought was to pay a SMS Gateway, the internet has thousands of them, easy to use, relatively cheap and fast to integrate.

But, there is always a but, I discovered that my customer has several Huawei E173 GSM USB modems with a SMS plan! They have the hardware, they already pay for SMS, so why not use these modems?!.

So here it is, a simple way to send SMS using a Huawei E173 GSM USB modem in a Ubuntu Server 12.04.

The E173 modem that I’m using, when plugged in, will emulate a CD-ROM driver containing the software needed by this modem. The modem device will not be available unless we “switch mode” the USB device, this is called a “flip flop” USB device. To handle that we need to install the usb_modeswitch(usb_modeswitch) if it isn’t already.

This command will install the usb-modeswitch and the gsm-utils that will do the magic:

apt-get install usb-modeswitch gsm-utils

Before connecting you modem to the USB port, run this command:

tail -f /var/log/syslog

Go ahead, connect the modem, wait some seconds(+5) and you will see something like this:

Apr 12 11:26:00 server kernel: [ 1862.731001] usb 1-1: new high-speed USB device number 3 using ehci_hcd
Apr 12 11:26:01 server kernel: [ 1863.381742] option 1-1:1.0: GSM modem (1-port) converter detected
Apr 12 11:26:01 server kernel: [ 1863.382231] usb 1-1: GSM modem (1-port) converter now attached to ttyUSB0
Apr 12 11:26:01 server kernel: [ 1863.382279] option 1-1:1.1: GSM modem (1-port) converter detected
Apr 12 11:26:01 server kernel: [ 1863.382321] usb 1-1: GSM modem (1-port) converter now attached to ttyUSB1
Apr 12 11:26:01 server kernel: [ 1863.385510] scsi4 : usb-storage 1-1:1.2
Apr 12 11:26:02 server kernel: [ 1864.386423] scsi 4:0:0:0: CD-ROM            HUAWEI   Mass Storage     2.31 PQ: 0 ANSI: 2
Apr 12 11:26:02 server kernel: [ 1864.398748] sr1: scsi-1 drive
Apr 12 11:26:02 server kernel: [ 1864.399381] sr 4:0:0:0: Attached scsi CD-ROM sr1
Apr 12 11:26:02 server kernel: [ 1864.400494] sr 4:0:0:0: Attached scsi generic sg2 type 5

Press Ctrl+C to exit tail.

If you see a line like this "GSM modem (1-port) converter now attached to ttyUSBX" means that your modem is ready to use.

And finally, how to send a SMS message(In my case my modem is in /dev/ttyUSB0 and the baudrate is 19200, change according to your setup):

echo "SMS Test Message!" | gsmsendsms -d /dev/ttyUSB0 -b 19200 PHONE_NUMBER

There should be no output. The exit code is 0 if everything is OK, greater than 0 if fail.

Great, I already can send SMS using the console, but I need to integrate into my application. The fastest and easiest way is to call the same command I ran in the console.

	public static boolean sendSmsSynchronous(final String phone, final String message)
	{
		final ProcessBuilder processBuilder = new ProcessBuilder().command("/usr/bin/gsmsendsms", "-d", "/dev/ttyUSB0", "-b", "19200", phone, message);
		Process gsmsendsmsProcess;
		try
		{
			gsmsendsmsProcess = processBuilder.start();
			gsmsendsmsProcess.waitFor();
		}
		catch (final Exception e)
		{
			return false;
		}

		return gsmsendsmsProcess.exitValue() == 0;
	}

That’s it, have fun!

Ps.: All the commands above must be run by root, if you aren’t root, just add sudo before.

Shutdown Windows KVM Virtual Machine

All my servers usually are Ubuntu Linux boxes. But sometimes I have to manage some Windows servers (2003, 2008, …) running in a KVM setup.

Every time that the host KVM server needs to be restarted, my Windows instances aren’t shutdown cleanly. If I open the virt-manager and open the Console, the screen is resumed(As when it is sleeping) and if I shutdown the host it will show that the Windows is shutting down and everything is perfect, but, there is always a but, if I do the shutdown by ssh without interacting with the Windows machine, it doesn’t “accept” the ACPI Shutdown command and just stand still.

Just for information, I already setup all the ACPI stuff in the KVM and in the Windows boxes.

To avoid this behavior I changed my libvirt script to send a mouse movement before the shutdown command, awaking the Windows before, so it can shutdown properly. 

Edit the upstart-job script:

vim /etc/init/libvirt-bin.conf

Add these 2 lines:

run_virsh -c "$uri" qemu-monitor-command "$domain" mouse_move 100 100 --hmp > /dev/null
sleep 2

Between the log message and the shutdown command:

log_msg "libvirt-bin: attempting clean shutdown of $domain at $(date)"
#
# ADD HERE
#
run_virsh -c "$uri" shutdown "$domain" > /dev/null

This will “awake” the Windows machine and shutdown it cleanly.

Hope it helps!

— Update June, 19 2013 —

Also you need to disable some dialogs in the Windows GPO and Registry to enable your machine shutdown unattended.

http://ethertubes.com/unattended-acpi-shutdown-of-windows-server/

— Update September, 12 2013 —

As noted by user infernix, the link I provided in the last update is offline. So I’ll write here what need to be done instead link to another page.

We need to disable a policy that in Windows Server machines will disallow shutdown if the administrator(Or other authorized user) is not logged in.

First, open the Group Policy Editor, press “Win + R” or open “Run” in the Start Menu, write “gpedit.msc”, hit Enter:

Step1

This will open the GP Editor, navigate to:

Local Computer Policy -> Computer Configuration -> Windows Settings -> Security Settings -> Local Policies -> Security Options

In the right panel, will be a option that says: “Shutdown: Allow system to be shut down without having to log on”. Double click it and select “Enabled”.

Step2

Secondly, we need to disable the “Shutdown Event Tracker”, which is the dialog that will be presented to the user when a shutdown is requested.

Navigate to:

Local Computer Policy -> Computer Configuration -> Administrative Templates -> System

In the right panel, disable the option “Display Shutdown Event Tracker”, the same way you did in the last step, but this time, “Disabled”.

Step3

An optional step is to disable monitor sleep, which will not change the power consumption as this is a virtual machine, with a virtual console and will avoid any other issues with shutdown.

Open Control Panel and select Power Options. I use “High performance” option, but you need to click on “Change plan settings” to disable monitor sleep, see images above.

Step4

Step5

Well, this is all folks.