253 lines
9.1 KiB
Python
253 lines
9.1 KiB
Python
"""The CardConnection abstract class manages connections with a card and
|
|
apdu transmission.
|
|
|
|
__author__ = "https://www.gemalto.com/"
|
|
|
|
Copyright 2001-2012 gemalto
|
|
Author: Jean-Daniel Aussel, mailto:jean-daniel.aussel@gemalto.com
|
|
|
|
This file is part of pyscard.
|
|
|
|
pyscard is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
(at your option) any later version.
|
|
|
|
pyscard 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 Lesser General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with pyscard; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
"""
|
|
|
|
from smartcard.CardConnectionEvent import CardConnectionEvent
|
|
from smartcard.Observer import Observable
|
|
|
|
|
|
class CardConnection(Observable):
|
|
"""Card connection abstract class."""
|
|
|
|
T0_protocol = 0x00000001
|
|
""" protocol T=0 """
|
|
|
|
T1_protocol = 0x00000002
|
|
""" protocol T=1 """
|
|
|
|
RAW_protocol = 0x00010000
|
|
""" protocol RAW (direct access to the reader) """
|
|
|
|
T15_protocol = 0x00000008
|
|
""" protocol T=15 """
|
|
|
|
def __init__(self, reader):
|
|
"""Construct a new card connection.
|
|
|
|
@param reader: name of the reader in which the smartcard to connect
|
|
to is located.
|
|
"""
|
|
Observable.__init__(self)
|
|
self.reader = reader
|
|
""" reader name """
|
|
self.errorcheckingchain = None
|
|
""" see L{setErrorCheckingChain} """
|
|
self.defaultprotocol = CardConnection.T0_protocol | CardConnection.T1_protocol
|
|
""" see L{setProtocol} and L{getProtocol} """
|
|
|
|
def __del__(self):
|
|
"""Connect to card."""
|
|
|
|
def addSWExceptionToFilter(self, exClass):
|
|
"""Add a status word exception class to be filtered.
|
|
|
|
@param exClass: the class to filter, e.g.
|
|
L{smartcard.sw.SWExceptions.WarningProcessingException}
|
|
|
|
Filtered exceptions will not be raised when encountered in the
|
|
error checking chain."""
|
|
if self.errorcheckingchain is not None:
|
|
self.errorcheckingchain[0].addFilterException(exClass)
|
|
|
|
def addObserver(self, observer):
|
|
"""Add a L{CardConnection} observer."""
|
|
Observable.addObserver(self, observer)
|
|
|
|
def deleteObserver(self, observer):
|
|
"""Remove a L{CardConnection} observer."""
|
|
Observable.deleteObserver(self, observer)
|
|
|
|
def connect(self, protocol=None, mode=None, disposition=None):
|
|
"""Connect to card.
|
|
@param protocol: a bit mask of the protocols to use, from
|
|
L{CardConnection.T0_protocol}, L{CardConnection.T1_protocol},
|
|
L{CardConnection.RAW_protocol}, L{CardConnection.T15_protocol}
|
|
|
|
@param mode: C{smartcard.scard.SCARD_SHARE_SHARED} (default),
|
|
C{smartcard.scard.SCARD_SHARE_EXCLUSIVE} or
|
|
C{smartcard.scard.SCARD_SHARE_DIRECT}
|
|
|
|
@param disposition: C{smartcard.scard.SCARD_LEAVE_CARD}
|
|
(default), C{smartcard.scard.SCARD_RESET_CARD},
|
|
C{smartcard.scard.SCARD_UNPOWER_CARD} or
|
|
C{smartcard.scard.SCARD_EJECT_CARD}
|
|
"""
|
|
# pylint: disable=unused-argument
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(self, CardConnectionEvent("connect"))
|
|
|
|
def reconnect(self, protocol=None, mode=None, disposition=None):
|
|
"""Reconnect to card.
|
|
@param protocol: a bit mask of the protocols to use, from
|
|
L{CardConnection.T0_protocol}, L{CardConnection.T1_protocol},
|
|
L{CardConnection.RAW_protocol}, L{CardConnection.T15_protocol}
|
|
|
|
@param mode: C{smartcard.scard.SCARD_SHARE_SHARED} (default),
|
|
C{smartcard.scard.SCARD_SHARE_EXCLUSIVE} or
|
|
C{smartcard.scard.SCARD_SHARE_DIRECT}
|
|
|
|
@param disposition: C{smartcard.scard.SCARD_LEAVE_CARD},
|
|
C{smartcard.scard.SCARD_RESET_CARD} (default),
|
|
C{smartcard.scard.SCARD_UNPOWER_CARD} or
|
|
C{smartcard.scard.SCARD_EJECT_CARD}
|
|
"""
|
|
# pylint: disable=unused-argument
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(self, CardConnectionEvent("reconnect"))
|
|
|
|
def disconnect(self):
|
|
"""Disconnect from card."""
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(self, CardConnectionEvent("disconnect"))
|
|
|
|
def release(self):
|
|
"""Release the context."""
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(self, CardConnectionEvent("release"))
|
|
|
|
def getATR(self):
|
|
"""Return card ATR"""
|
|
|
|
def getProtocol(self):
|
|
"""Return bit mask for the protocol of connection, or None if no
|
|
protocol set. The return value is a bit mask of
|
|
L{CardConnection.T0_protocol}, L{CardConnection.T1_protocol},
|
|
L{CardConnection.RAW_protocol}, L{CardConnection.T15_protocol}
|
|
"""
|
|
return self.defaultprotocol
|
|
|
|
def getReader(self):
|
|
"""Return card connection reader"""
|
|
return self.reader
|
|
|
|
def setErrorCheckingChain(self, errorcheckingchain):
|
|
"""Add an error checking chain.
|
|
@param errorcheckingchain: a L{smartcard.sw.ErrorCheckingChain}
|
|
object The error checking strategies in errorchecking chain will
|
|
be tested with each received response APDU, and a
|
|
L{smartcard.sw.SWExceptions.SWException} will be raised upon
|
|
error."""
|
|
self.errorcheckingchain = errorcheckingchain
|
|
|
|
def setProtocol(self, protocol):
|
|
"""Set protocol for card connection.
|
|
@param protocol: a bit mask of L{CardConnection.T0_protocol},
|
|
L{CardConnection.T1_protocol}, L{CardConnection.RAW_protocol},
|
|
L{CardConnection.T15_protocol}
|
|
|
|
>>> setProtocol(CardConnection.T1_protocol | CardConnection.T0_protocol)
|
|
"""
|
|
self.defaultprotocol = protocol
|
|
|
|
def transmit(self, command, protocol=None):
|
|
"""Transmit an apdu. Internally calls L{doTransmit()} class method
|
|
and notify observers upon command/response APDU events.
|
|
Subclasses must override the L{doTransmit()} class method.
|
|
|
|
@param command: list of bytes to transmit
|
|
|
|
@param protocol: the transmission protocol, from
|
|
L{CardConnection.T0_protocol},
|
|
L{CardConnection.T1_protocol}, or
|
|
L{CardConnection.RAW_protocol}
|
|
"""
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(
|
|
self, CardConnectionEvent("command", [command, protocol])
|
|
)
|
|
data, sw1, sw2 = self.doTransmit(command, protocol)
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(
|
|
self, CardConnectionEvent("response", [data, sw1, sw2])
|
|
)
|
|
if self.errorcheckingchain is not None:
|
|
self.errorcheckingchain[0](data, sw1, sw2)
|
|
return data, sw1, sw2
|
|
|
|
def doTransmit(self, command, protocol):
|
|
"""Performs the command APDU transmission.
|
|
|
|
Subclasses must override this method for implementing apdu
|
|
transmission."""
|
|
# pylint: disable=unused-argument
|
|
return [], 0, 0
|
|
|
|
def control(self, controlCode, command=None):
|
|
"""Send a control command and buffer. Internally calls
|
|
L{doControl()} class method and notify observers upon
|
|
command/response events. Subclasses must override the
|
|
L{doControl()} class method.
|
|
|
|
@param controlCode: command code
|
|
|
|
@param command: list of bytes to transmit
|
|
"""
|
|
if command is None:
|
|
command = []
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(
|
|
self, CardConnectionEvent("command", [controlCode, command])
|
|
)
|
|
data = self.doControl(controlCode, command)
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(self, CardConnectionEvent("response", data))
|
|
if self.errorcheckingchain is not None:
|
|
self.errorcheckingchain[0](data)
|
|
return data
|
|
|
|
def doControl(self, controlCode, command):
|
|
"""Performs the command control.
|
|
|
|
Subclasses must override this method for implementing control."""
|
|
# pylint: disable=unused-argument
|
|
return []
|
|
|
|
def getAttrib(self, attribId):
|
|
"""return the requested attribute
|
|
|
|
@param attribId: attribute id like
|
|
C{smartcard.scard.SCARD_ATTR_VENDOR_NAME}
|
|
"""
|
|
Observable.setChanged(self)
|
|
Observable.notifyObservers(self, CardConnectionEvent("attrib", [attribId]))
|
|
data = self.doGetAttrib(attribId)
|
|
if self.errorcheckingchain is not None:
|
|
self.errorcheckingchain[0](data)
|
|
return data
|
|
|
|
def doGetAttrib(self, attribId):
|
|
"""Performs the command get attrib.
|
|
|
|
Subclasses must override this method for implementing get attrib."""
|
|
# pylint: disable=unused-argument
|
|
return []
|
|
|
|
def __enter__(self):
|
|
"""Enter the runtime context."""
|
|
return self
|
|
|
|
def __exit__(self, e_type, value, traceback):
|
|
"""Exit the runtime context trying to disconnect."""
|
|
self.disconnect()
|