Skip to content

cardconnect

Petr Tobiska edited this page Feb 15, 2016 · 1 revision

Choose and connect your reader

Rudimentary connection

In order to communicate with smartcard you need to first connect your reader. Using pyscard, the procedure is basically

from smartcard.System import readers
r = readers()
c = r[0].createConnection()
c.connect()

In the second line, a list of available readers is returned (a reader is <class 'smartcard.pcsc.PCSCReader.PCSCReader'>), in the third line you choose one of them (the first one in our case) and create connection for it, in fact:

>>> type( c )
<class 'smartcard.CardConnectionDecorator.CardConnectionDecorator'>

and finally you connect to it in the fourth line.

Connect using mycard.connectCard()

As you may have more readers connected, it is inconvenient to hard-code an index of reader to use. In asterix, the required reader is chosen based on reader names presented by PCSC subsystem to pyscard. E.g. on Windows you may have

>>> readers()
['Broadcom Corp Contacted SmartCard 0', 'Gemalto Prox-DU Contact_14603441 0', 'Gemalto Prox-DU Contactless_14603441 1', 'Gemalto Virtual Card Simulator Reader 0', 'Gemplus USB Smart Card Reader 0']

and you want to communicate with card in the reader Gemplus USB Smart Card Reader 0. In asterix you achieve it by

from asterix import mycard
c = mycard.connectCard( 'USB' )

The reader used is announced by a message:

>>> Connecting to Gemplus USB Smart Card Reader 0

Why 'USB'? The argument arg of connectCard( arg ) forms a regular expression '.*'+arg+'.*' and it is matched against names of readers known to pyscard. If there is just one name matching, it is used for creating the connection. Otherwise a message like this is displayed:

Non uniq connections: ['Gemalto USB Smart Card Reader 2', 'Gemplus USB Smart Card Reader 0']

(in case you attach the second matching reader) or

Non uniq connections: []

if no match is found at all.

You may easily find which readers are available to your system by calling connectCard() with no argument. Default argument is an empty string so all readers available to pyscard match.

Enhancements of mycard.connectCard()

Three enhancements are implemented by connectCard() function

APDU trace

Pyscard allows you to trigger a function when data are transmitted to or from the card. It uses CardConnectionObserver object for it. In asterix, a console observer writes to stdout APDU transmitted to the card and the response from the card. For example Select APDU and returned Status word (SW):

 => 00A4 0400 0E 325041592E5359532E4444463031
 <= 611B

Time spent by APDU processing

For some applications, one is interested in time spent by APDU processing. In asterix you may switch it on by mycard.dispTime( c, True ) or switch it off by mycard.dispTime( c, False ). Time is displayed in milliseconds (with 100ns granularity) after data/SW returned from the card (currently works on Windows and linux):

 => 00A4 0400 0E 325041592E5359532E4444463031
 <= 611B
time: 6.8083 ms

To switch on, you may omit True argument to dispTime() call (default value True is supplied).

By default, displaying of time is switched off.

The first argument, c is a <CardConnectionDecorator>, so you may applied it to SCP02Connection or SCP03Connection derived from c (see details TBD).

GAF

In pyscard, you send APDU and receive a response as a list of bytes:

>>> resp, sw1, sw2 = c.transmit( [0, 164, 4, 0, 14, 50, 80, 65, 89, 46, 83, 89, 83, 46, 68, 68, 70, 48, 49] )
 => 00A4 0400 0E 325041592E5359532E4444463031
 <= 611B
>>> resp, sw1, sw2 = c.transmit( [ 0, 192, 0, 0, sw2] )
 => 00C0 0000 1B 
 <= 6F19840E325041592E5359532E4444463031A5079F080110890102 9000

It is not quite convenient for interactive work. In the module asterix.mycard a new class GAFConnection as extension of the class CardConnectionDecorator is implemented (in fact connectCard() returns you its instance). It implements a method send( templ, **kw ) which first create GAF from a template templ and evaluates it (allowing variable substitution from a dictionary kw). The previous example become (note that it also sends Get Response in Case 4 APDU in order to receive returned data):

>>> resp, sw = c.send( "00A4 0400 #[ '2PAY.SYS.DDF01' ]" )
 => 00A4 0400 0E 325041592E5359532E4444463031
 <= 611B
 => 00C0 0000 1B 
 <= 6F19840E325041592E5359532E4444463031A5079F080110890102 9000

See details about GAF on its page

Clone this wiki locally