PCSC sample in Perl

Here is the PCSC sample in Perl language I promised in PC/SC sample in different languages.

Installation

Get the source code from http://ludovic.rousseau.free.fr/softwares/pcsc-perl/. The current version is 1.4.8. If you distribution does not provide a package (Debian does with libpcsc-perl) you can install it by hand using:

pcsc-perl-1.4.8$ perl Makefile.PL 
osname: linux
LDDFLAGS: 
INC: `pkg-config --cflags libpcsclite`
Checking if your kit is complete...
Looks good
Writing Makefile for Chipcard::PCSC::Card
Writing Makefile for Chipcard::PCSC
pcsc-perl-1.4.7$ make
[...]
pcsc-perl-1.4.7$ make test
[...]
pcsc-perl-1.4.7$ make install
[...]

The wrapper works on GNU/Linux, Mac OS X and Windows.

API


The API documentation is available online at http://ludovic.rousseau.free.fr/softwares/pcsc-perl/PCSC.html and http://ludovic.rousseau.free.fr/softwares/pcsc-perl/Card.html.

You can also have a look at the project page project page on CPAN (Comprehensive Perl Archive Network).

Source code


#!/usr/bin/perl -w

use Chipcard::PCSC;

# create a new object
$hContext = new Chipcard::PCSC();
die ("Can't create the PCSC object: $Chipcard::PCSC::errno\n")
    unless defined $hContext;

# get the reader list
@ReadersList = $hContext->ListReaders();
die ("Can't get readers' list: $Chipcard::PCSC::errno\n")
    unless defined $ReadersList[0];

# connect to the first reader
$hCard = new Chipcard::PCSC::Card($hContext, $ReadersList[0]);
die ("Can't connect: $Chipcard::PCSC::errno\n")
    unless defined $hCard;

# send the Select Applet APDU
$cmd = Chipcard::PCSC::ascii_to_array("00 A4 04 00 0A A0 00 00 00 62 03 01 0C 06 01");
$RecvData = $hCard->Transmit($cmd);
die ("Can't transmit data: $Chipcard::PCSC::errno") unless defined $RecvData;
print Chipcard::PCSC::array_to_ascii($RecvData)."\n";

# send the test APDU
$cmd = Chipcard::PCSC::ascii_to_array("00 00 00 00");
$RecvData = $hCard->Transmit($cmd);
die ("Can't transmit data: $Chipcard::PCSC::errno") unless defined $RecvData;
print Chipcard::PCSC::array_to_ascii($RecvData)."\n";

$hCard->Disconnect();

Output


90 00
48 65 6C 6C 6F 20 77 6F 72 6C 64 21 90 00

Lessons learned


Portability


The same code can be used on any plateform. No more #ifdef like in C.

Low level API


The API is still low level and just wrap PC/SC calls from C to Perl.

Higher level API


TransmitWithCheck() is a little more easy to use than Transmit(). This method does the split between data and status word.

In the example above replace the two last blocks with:

# Send the Select Applet APDU
($sw, $RecvData) = $hCard->TransmitWithCheck("00 A4 04 00 0A A0 00 00 00 62 03 01 0C 06 01", "90 00");
die ("Can't transmit data: $Chipcard::PCSC::errno") unless defined $sw;
print $RecvData."\n";
print Chipcard::PCSC::Card::ISO7816Error($sw) . " ($sw)\n";

# Send the test APDU
($sw, $RecvData) = $hCard->TransmitWithCheck("00 00 00 00", "90 00");
die ("Can't transmit data: $Chipcard::PCSC::errno") unless defined $sw;
print $RecvData."\n";
print map { chr hex $_ } split ' ', $RecvData;
print "\n";
print Chipcard::PCSC::Card::ISO7816Error($sw) . " ($sw)\n";

This sample code also uses Chipcard::PCSC::Card::ISO7816Error($sw) to transform the status word is something human readable like Normal processing. for 90 00.

Output


Normal processing. (90 00)
48 65 6C 6C 6F 20 77 6F 72 6C 64 21 
Hello world!
Normal processing. (90 00)