[Pcsclite-cvs-commit] r6945 - in trunk/HandlerTest: . PCSC

ludovic.rousseau at free.fr ludovic.rousseau at free.fr
Thu Jul 31 09:08:03 UTC 2014


Author: rousseau
Date: 2014-07-31 09:08:03 +0000 (Thu, 31 Jul 2014)
New Revision: 6945

Added:
   trunk/HandlerTest/PCSC/
   trunk/HandlerTest/PCSC/validation.py
Log:
validation.py: perform exchanges with all APDU sizes possible

This is a Python version of handler_test.c
- shorter code thanks to Python
- use PC/SC interface so easy to use (in particular on Mac OS X)
- use PC/SC to also check PC/SC bugs or limitations (like on Mac OS X)


Added: trunk/HandlerTest/PCSC/validation.py
===================================================================
--- trunk/HandlerTest/PCSC/validation.py	                        (rev 0)
+++ trunk/HandlerTest/PCSC/validation.py	2014-07-31 09:08:03 UTC (rev 6945)
@@ -0,0 +1,340 @@
+#! /usr/bin/env python
+
+"""
+#    validation.py: perform exchanges with all APDU sizes possible
+#    Copyright (C) 2014  Ludovic Rousseau
+#
+#    This program is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License along
+#    with this program; if not, write to the Free Software Foundation, Inc.,
+#    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+"""
+
+from smartcard.System import readers
+from smartcard.util import toBytes, toHexString
+from smartcard.CardConnectionObserver import ConsoleCardConnectionObserver
+
+
+def print_error(text):
+    RED = '\033[01;31m'
+    NORMAL = '\033[0m'
+    print RED + text + NORMAL
+
+
+class Validation(object):
+    def __init__(self, reader, extended=False, debug=False):
+        self.reader = reader
+
+        # Begining Of Line
+        import curses
+        curses.setupterm()
+        self.BOL = curses.tigetstr("cr") + curses.tigetstr("cuu1")
+
+        # connect to the reader
+        self.connection = reader.createConnection()
+
+        # create an observer to get debug
+        if debug:
+            observer = ConsoleCardConnectionObserver()
+            self.connection.addObserver(observer)
+            self.BOL = ""
+
+        # connect using any protocol
+        self.connection.connect()
+
+        # get the ATR
+        self.ATR = self.connection.getATR()
+
+        # extended APDU
+        self.extended = extended
+
+        # select APDU
+        if not extended:
+            SELECT = toBytes("00 A4 04 00 06 A0 00 00 00 18 FF")
+            expected = [[], 0x90, 0x00]
+            self.transmitAndCompare(SELECT, expected)
+
+    def transmitAndCompare(self, apdu, expected):
+        r_data, r_sw1, r_sw2 = self.connection.transmit(apdu)
+        e_data, e_sw1, e_sw2 = expected
+        if r_sw1 != e_sw1 or r_sw2 != e_sw2:
+            print_error("Wrong SW: %02X %02X instead of %02X %02X" %
+                    (r_sw1, r_sw2, e_sw1, e_sw2))
+            raise Exception("Fail!")
+        if r_data != e_data:
+            print_error("Wrong data")
+            print "Received:", r_data
+            print "Expected:", e_data
+            raise Exception("Fail!")
+
+    def case_1(self, full):
+        # no data exchanged
+        # >  80 30 00 00 00
+        # <  []  90 0
+        CASE_1 = toBytes("80 30 00 00 00")
+
+        print "Case 1"
+
+        expected = ([], 0x90, 0x00)
+        self.transmitAndCompare(CASE_1, expected)
+
+    def case_2(self, full):
+        if self.extended:
+            self.case_2e(full)
+        else:
+            self.case_2s(full)
+
+    def case_2s(self, full):
+        # gets (1 to 256) data from the card
+        # >  80 34 00 07 07
+        # <  00 01 02 03 04 05 06 90 0
+        CASE_2 = toBytes("80 34 00 00 00")
+
+        print "Case 2 short"
+        print
+
+        end = 256
+        if full:
+            start = 1
+        else:
+            start = end
+
+        for length in range(start, end + 1):
+            print self.BOL, "length:", length
+            APDU = list(CASE_2)
+            APDU[2] = (length & 0xFF00) >> 8
+            APDU[3] = length & 0x00FF
+            APDU[4] = length & 0x00FF
+
+            expected = ([i for i in range(0, length)], 0x90, 0x00)
+            self.transmitAndCompare(APDU, expected)
+
+    def case_2e(self, full):
+        # gets (1 to 256) data from the card
+        # >  80 00 04 2A 00 00 07
+        # <  2A 2A 2A 2A 2A 2A 2A 90 0
+        magic_value = 42
+        CASE_2 = toBytes("80 00 04 00 00 00 00")
+        CASE_2[3] = magic_value
+
+        print "Case 2 extended"
+        print
+
+        if toHexString(self.ATR) != "3B D6 18 00 80 B1 80 6D 1F 03 80 51 00 61 10 30 9E":
+            print_error("Wrong card inserted!")
+            print "Got ATR:", toHexString(self.ATR)
+            return
+
+        step = 100
+        end = 65535
+        if full:
+            start = 1
+        else:
+            start = end
+
+        for length in range(start, end + 1, step):
+            print self.BOL, "length:", length
+            APDU = list(CASE_2)
+            APDU[5] = (length & 0xFF00) >> 8
+            APDU[6] = length & 0x00FF
+
+            expected = ([magic_value] * length, 0x90, 0x00)
+            self.transmitAndCompare(APDU, expected)
+
+    def case_3(self, full):
+        if self.extended:
+            self.case_3e(full)
+        else:
+            self.case_3s(full)
+
+    def case_3s(self, full):
+        # send data to the card
+        # >  80 32 00 00 07 00 01 02 03 04 05 06
+        # <  []  90 0
+        CASE_3 = toBytes("80 32 00 00 00")
+
+        print "Case 3 short"
+        print
+
+        end = 255
+        if full:
+            start = 1
+        else:
+            start = end
+
+        expected = ([], 0x90, 0x00)
+        for length in range(start, end + 1):
+            print self.BOL, "length:", length
+            APDU = list(CASE_3)
+            APDU[4] = length
+            APDU += [i for i in range(0, length)]
+
+            self.transmitAndCompare(APDU, expected)
+
+    def case_3e(self, full):
+        # send data to the card
+        # >  80 12 01 80 00 00 07 00 01 02 03 04 05 06
+        # <  []  90 0
+        CASE_3 = toBytes("80 12 01 80 00 00 00")
+
+        print "Case 3 extended"
+        print
+
+        if toHexString(self.ATR) != "3B D6 18 00 81 B1 80 7D 1F 03 80 51 00 61 10 30 8F":
+            print_error("Wrong card inserted!")
+            print "Got ATR:", toHexString(self.ATR)
+            return
+
+        end = 65535
+        step = 100
+        if full:
+            start = 1
+        else:
+            start = end
+
+        expected = ([], 0x90, 0x00)
+        for length in range(start, end + 1, step):
+            print self.BOL, "length:", length
+            APDU = list(CASE_3)
+            APDU[5] = (length & 0xFF00) >> 8
+            APDU[6] = length & 0x00FF
+            APDU += [i for i in range(0, length)]
+
+            self.transmitAndCompare(APDU, expected)
+
+    def case_4(self, full, apdu):
+        # send data to the card and get response
+        # mode APDU (T=1)
+        # >  80 36 00 09 08 00 01 02 03 04 05 06 07
+        # <  00 01 02 03 04 05 06 07 08 90 0
+        # mode TPDU (T=0)
+        # >  80 36 00 09 08 00 01 02 03 04 05 06 07
+        # <  []  61 9
+        # >  80 C0 00 00 09
+        # <  00 01 02 03 04 05 06 07 08 90 0
+        CASE_2 = toBytes("80 36 00 00 00")
+
+        print "Case 4"
+        print
+
+        end = 255
+        if full:
+            start = 1
+        else:
+            start = 255
+
+        for length_in in range(start, end + 1):
+            print self.BOL, "length:", length_in
+            length_out = length_in + 1
+            APDU = list(CASE_2)
+            APDU[2] = (length_out & 0xFF00) >> 8
+            APDU[3] = (length_out & 0x00FF)
+            APDU[4] = length_in
+            APDU += [i for i in range(0, length_in)]
+
+            if apdu:
+                expected = ([i for i in range(0, length_out)], 0x90, 0x00)
+                self.transmitAndCompare(APDU, expected)
+            else:
+                expected = ([], 0x61, length_out & 0xFF)
+                self.transmitAndCompare(APDU, expected)
+
+                GET_RESPONSE = toBytes("80 C0 00 00 00")
+                GET_RESPONSE[4] = length_out & 0xFF
+
+                expected = ([i for i in range(0, length_out)], 0x90, 0x00)
+                self.transmitAndCompare(GET_RESPONSE, expected)
+
+    def time_extension(self, extension):
+        # time extension
+        TIME = toBytes("80 38 00 00")
+        TIME[3] = extension
+
+        expected = ([], 0x90, 0x00)
+        self.transmitAndCompare(TIME, expected)
+
+
+def usage(command):
+    HELP = """ Possible arguments:
+  -1: test APDU Case 1
+  -2: test APDU Case 2
+  -3: test APDU Case 3
+  -4: test APDU Case 4
+  -e: test extended APDU (using PC/SC test cards)
+  -f: test APDU with every possible lengths
+  -r: reader index. By default the first reader is used
+  -a: use APDU
+  -d: debug mode
+  -t val: use val as timerequest value"""
+    print "Usage: %s [arguments]" % command
+    print HELP
+
+if __name__ == "__main__":
+    import sys
+    import getopt
+
+    optlist, args = getopt.getopt(sys.argv[1:], "1234r:ft:aedh")
+
+    case_1 = False
+    case_2 = False
+    case_3 = False
+    case_4 = False
+    full = False
+    apdu = False
+    time_extension = False
+    extended = False
+    debug = False
+
+    for o, a in optlist:
+        if o == "-1":
+            case_1 = True
+        elif o == "-2":
+            case_2 = True
+        elif o == "-3":
+            case_3 = True
+        elif o == "-4":
+            case_4 = True
+        elif o == "-r":
+            reader_index = int(a)
+        elif o == "-f":
+            full = True
+        elif o == "-a":
+            apdu = True
+        elif o == "-t":
+            time_extension = True
+            extension = int(a)
+        elif o == "-e":
+            extended = True
+        elif o == "-d":
+            debug = True
+        elif o == "-h":
+            usage(sys.argv[0])
+            sys.exit()
+
+    readers = readers()
+    try:
+        reader = readers[reader_index]
+    except:
+        reader = readers[0]
+    print "Using reader:", reader
+
+    validation = Validation(reader, extended=extended, debug=debug)
+    if case_1:
+        validation.case_1(full)
+    if case_2:
+        validation.case_2(full)
+    if case_3:
+        validation.case_3(full)
+    if case_4:
+        validation.case_4(full, apdu)
+    if time_extension:
+        validation.time_extension(extension)


Property changes on: trunk/HandlerTest/PCSC/validation.py
___________________________________________________________________
Added: svn:executable
   + *




More information about the Pcsclite-cvs-commit mailing list