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)