| 1 |
lvictor |
3506 |
#!/usr/bin/perl -w |
| 2 |
lvictor |
3504 |
|
| 3 |
rousseau |
3510 |
# scriptor.pl: text interface to send APDU commands to a smart card |
| 4 |
|
|
# Copyright (C) 2001 Lionel Victor |
| 5 |
rousseau |
3626 |
# 2002-2003 Ludovic Rousseau |
| 6 |
rousseau |
3510 |
# |
| 7 |
|
|
# This program is free software; you can redistribute it and/or modify |
| 8 |
|
|
# it under the terms of the GNU General Public License as published by |
| 9 |
|
|
# the Free Software Foundation; either version 2 of the License, or |
| 10 |
|
|
# (at your option) any later version. |
| 11 |
|
|
# |
| 12 |
|
|
# This program is distributed in the hope that it will be useful, |
| 13 |
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 |
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 |
|
|
# GNU General Public License for more details. |
| 16 |
|
|
# |
| 17 |
|
|
# You should have received a copy of the GNU General Public License |
| 18 |
|
|
# along with this program; if not, write to the Free Software |
| 19 |
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 20 |
|
|
|
| 21 |
rousseau |
3954 |
# $Id: scriptor,v 1.19 2007-05-19 13:15:01 rousseau Exp $ |
| 22 |
rousseau |
3510 |
|
| 23 |
lvictor |
3504 |
use Getopt::Std; |
| 24 |
rousseau |
3626 |
use Chipcard::PCSC; |
| 25 |
|
|
use Chipcard::PCSC::Card; |
| 26 |
lvictor |
3504 |
|
| 27 |
|
|
use strict; |
| 28 |
rousseau |
3649 |
use warnings; |
| 29 |
lvictor |
3504 |
|
| 30 |
|
|
my %options; |
| 31 |
|
|
|
| 32 |
rousseau |
3626 |
my $hContext = new Chipcard::PCSC(); |
| 33 |
lvictor |
3504 |
my $hCard; |
| 34 |
|
|
my @out_buffer; |
| 35 |
|
|
my $in_buffer; |
| 36 |
rousseau |
3954 |
my $echo; |
| 37 |
lvictor |
3504 |
|
| 38 |
rousseau |
3626 |
die ("Could not create Chipcard::PCSC object: $Chipcard::PCSC::errno\n") unless defined $hContext; |
| 39 |
lvictor |
3504 |
|
| 40 |
rousseau |
3649 |
getopt ("r:p:" , \%options); |
| 41 |
lvictor |
3504 |
|
| 42 |
|
|
if ($options{h}) { |
| 43 |
rousseau |
3649 |
print "Usage: $0 [-h] [-r reader] [-p protocol] [file]\n"; |
| 44 |
|
|
print " -h: this help\n"; |
| 45 |
|
|
print " -r reader: specify to use the PCSC smart card reader named reader\n"; |
| 46 |
|
|
print " By defaults the first one found is used so you\n"; |
| 47 |
|
|
print " don't have to specify anything if you just have\n"; |
| 48 |
|
|
print " one reader\n"; |
| 49 |
rousseau |
3667 |
print " -p protocol: protocol to use among T=0 and T=1.\n"; |
| 50 |
|
|
print " Default is to let pcsc-lite choose the protocol\n"; |
| 51 |
rousseau |
3649 |
print " file: file containing APDUs\n"; |
| 52 |
lvictor |
3504 |
exit (0); |
| 53 |
|
|
} |
| 54 |
|
|
|
| 55 |
rousseau |
3649 |
# protocol option |
| 56 |
|
|
if ($options{p}) { |
| 57 |
|
|
if ($options{p} =~ m/T=0/) { |
| 58 |
rousseau |
3669 |
print STDERR "Trying T=0 protocol\n"; |
| 59 |
rousseau |
3649 |
$options{p} = $Chipcard::PCSC::SCARD_PROTOCOL_T0; |
| 60 |
|
|
} else { |
| 61 |
|
|
if ($options{p} =~ m/T=1/) { |
| 62 |
rousseau |
3669 |
print STDERR "Trying T=1 protocol\n"; |
| 63 |
rousseau |
3649 |
$options{p} = $Chipcard::PCSC::SCARD_PROTOCOL_T1; |
| 64 |
|
|
} else { |
| 65 |
|
|
die "unknown protocol: $options{p}\n"; |
| 66 |
|
|
} |
| 67 |
|
|
} |
| 68 |
|
|
} else { |
| 69 |
rousseau |
3667 |
$options{p} = $Chipcard::PCSC::SCARD_PROTOCOL_T0 | $Chipcard::PCSC::SCARD_PROTOCOL_T1; |
| 70 |
rousseau |
3649 |
} |
| 71 |
|
|
|
| 72 |
|
|
# reader option |
| 73 |
lvictor |
3504 |
if ($options{r}) { |
| 74 |
lvictor |
3506 |
print STDERR "Using given card reader: $options{r}\n"; |
| 75 |
lvictor |
3504 |
} else { |
| 76 |
|
|
my @readers_list = $hContext->ListReaders (); |
| 77 |
rousseau |
3667 |
die ("Can't get readers list\n") unless defined $readers_list[0]; |
| 78 |
lvictor |
3506 |
print STDERR "No reader given: using $readers_list[0]\n"; |
| 79 |
rousseau |
3649 |
$options{r} = $readers_list[0]; |
| 80 |
lvictor |
3504 |
} |
| 81 |
|
|
|
| 82 |
rousseau |
3649 |
$hCard = new Chipcard::PCSC::Card ($hContext, $options{r}, $Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, $options{p}); |
| 83 |
|
|
die ("Can't allocate Chipcard::PCSC::Card object: $Chipcard::PCSC::errno\n") unless defined $hCard; |
| 84 |
|
|
|
| 85 |
rousseau |
3668 |
if ($hCard->{dwProtocol} == $Chipcard::PCSC::SCARD_PROTOCOL_T0) { |
| 86 |
|
|
print "Using T=0 protocol\n"; |
| 87 |
|
|
} else { |
| 88 |
|
|
if ($hCard->{dwProtocol} == $Chipcard::PCSC::SCARD_PROTOCOL_T1) { |
| 89 |
|
|
print "Using T=1 protocol\n"; |
| 90 |
|
|
} |
| 91 |
|
|
else { |
| 92 |
|
|
print "Using an unknown protocol (not T=0 or T=1)\n"; |
| 93 |
|
|
} |
| 94 |
|
|
} |
| 95 |
|
|
|
| 96 |
rousseau |
3649 |
# file option |
| 97 |
lvictor |
3504 |
if ($ARGV[0]) { |
| 98 |
lvictor |
3506 |
open (IN_FILEHANDLE, "<$ARGV[0]") or die ("Can't open $ARGV[0]: $!\n"); |
| 99 |
|
|
print STDERR "Using given file: $ARGV[0]\n"; |
| 100 |
rousseau |
3954 |
$echo=1; |
| 101 |
lvictor |
3504 |
} else { |
| 102 |
|
|
*IN_FILEHANDLE = *STDIN; |
| 103 |
|
|
print STDERR "Reading commands from STDIN\n"; |
| 104 |
rousseau |
3954 |
$echo=0; |
| 105 |
lvictor |
3504 |
} |
| 106 |
|
|
|
| 107 |
|
|
*OUT_FILEHANDLE = *STDOUT; |
| 108 |
|
|
|
| 109 |
rousseau |
3867 |
my $cmd; |
| 110 |
rousseau |
3868 |
my $match = ".. " x 24; |
| 111 |
lvictor |
3504 |
while (<IN_FILEHANDLE>) { |
| 112 |
|
|
my $tmp_value; |
| 113 |
rousseau |
3868 |
my ($SendData, $RecvData, $sw); |
| 114 |
lvictor |
3504 |
|
| 115 |
rousseau |
3954 |
print if ($echo); |
| 116 |
rousseau |
3558 |
last if /exit/i; |
| 117 |
lvictor |
3504 |
next if /^\s*$/; |
| 118 |
|
|
next if /^#/; |
| 119 |
|
|
|
| 120 |
rousseau |
3558 |
if (/reset/i) { |
| 121 |
lvictor |
3508 |
print OUT_FILEHANDLE "> RESET\n"; |
| 122 |
rousseau |
3626 |
if (defined $hCard->Reconnect ($Chipcard::PCSC::SCARD_SHARE_EXCLUSIVE, |
| 123 |
rousseau |
3649 |
$options{p}, |
| 124 |
rousseau |
3626 |
$Chipcard::PCSC::SCARD_RESET_CARD)) { |
| 125 |
rousseau |
3656 |
my @s = $hCard->Status(); |
| 126 |
|
|
print OUT_FILEHANDLE "< OK: "; |
| 127 |
|
|
print map { sprintf ("%02X ", $_) } @{$s[3]}; |
| 128 |
|
|
print OUT_FILEHANDLE "\n"; |
| 129 |
lvictor |
3508 |
} else { |
| 130 |
rousseau |
3626 |
print OUT_FILEHANDLE "< KO: $Chipcard::PCSC::errno\n"; |
| 131 |
lvictor |
3508 |
} |
| 132 |
|
|
next; |
| 133 |
|
|
} |
| 134 |
lvictor |
3506 |
chomp; |
| 135 |
rousseau |
3705 |
|
| 136 |
|
|
# if the command does not contains spaces (00A4030000) we expand it |
| 137 |
|
|
s/(..)/$1 /g if (! m/ /); |
| 138 |
|
|
|
| 139 |
rousseau |
3867 |
# continue if line ends in \ |
| 140 |
|
|
if (m/\\$/) |
| 141 |
|
|
{ |
| 142 |
|
|
chop; # remove the \ |
| 143 |
|
|
s/ *$/ /; # replace any spaces by ONE space |
| 144 |
|
|
$cmd .= $_; |
| 145 |
|
|
next; # read next line |
| 146 |
|
|
} |
| 147 |
|
|
|
| 148 |
|
|
$cmd .= $_; |
| 149 |
|
|
|
| 150 |
rousseau |
3705 |
# convert in an array (internal format) |
| 151 |
rousseau |
3626 |
$SendData = Chipcard::PCSC::ascii_to_array($cmd); |
| 152 |
lvictor |
3504 |
|
| 153 |
lvictor |
3506 |
print OUT_FILEHANDLE "> $cmd\n"; |
| 154 |
|
|
$RecvData = $hCard->Transmit($SendData); |
| 155 |
rousseau |
3626 |
die ("Can't get info: $Chipcard::PCSC::errno\n") unless defined $RecvData; |
| 156 |
rousseau |
3656 |
my $res = Chipcard::PCSC::array_to_ascii($RecvData); |
| 157 |
rousseau |
3868 |
$sw = Chipcard::PCSC::Card::ISO7816Error(substr($res, -5)); |
| 158 |
|
|
$res =~ s/($match)/$1\n/g; |
| 159 |
rousseau |
3695 |
print OUT_FILEHANDLE "< $res : " . Chipcard::PCSC::Card::ISO7816Error(substr($res, -5)) . "\n"; |
| 160 |
rousseau |
3867 |
|
| 161 |
|
|
# empty the command |
| 162 |
|
|
$cmd = ""; |
| 163 |
lvictor |
3504 |
} |
| 164 |
|
|
|
| 165 |
|
|
close (IN_FILEHANDLE); |
| 166 |
rousseau |
3626 |
$hCard->Disconnect($Chipcard::PCSC::SCARD_LEAVE_CARD); |
| 167 |
lvictor |
3504 |
$hCard = undef; |
| 168 |
|
|
$hContext = undef; |
| 169 |
|
|
|
| 170 |
|
|
# End of File |
| 171 |
lvictor |
3506 |
|