moved RelayOS into separate file
This commit is contained in:
@@ -23,6 +23,7 @@ vpicc_PYTHON = virtualsmartcard/CardGenerator.py \
|
||||
vpicccards_PYTHON = virtualsmartcard/cards/__init__.py \
|
||||
virtualsmartcard/cards/ePass.py \
|
||||
virtualsmartcard/cards/nPA.py \
|
||||
virtualsmartcard/cards/Relay.py \
|
||||
virtualsmartcard/cards/cryptoflex.py
|
||||
|
||||
do_subst = $(SED) \
|
||||
|
||||
@@ -23,7 +23,7 @@ from virtualsmartcard.SmartcardFilesystem import make_property
|
||||
from virtualsmartcard.utils import C_APDU, R_APDU, hexdump, inttostring
|
||||
from virtualsmartcard.CardGenerator import CardGenerator
|
||||
|
||||
import socket, struct, sys, signal, atexit, smartcard, logging
|
||||
import socket, struct, sys, signal, atexit, logging
|
||||
|
||||
|
||||
class SmartcardOS(object):
|
||||
@@ -397,111 +397,6 @@ class CryptoflexOS(Iso7816OS):
|
||||
return r
|
||||
|
||||
|
||||
class RelayOS(SmartcardOS):
|
||||
"""
|
||||
This class implements relaying of a (physical) smartcard. The RelayOS
|
||||
forwards the command APDUs received from the vpcd to the real smartcard via
|
||||
an actual smart card reader and sends the responses back to the vpcd.
|
||||
This class can be used to implement relay or MitM attacks.
|
||||
"""
|
||||
def __init__(self, readernum):
|
||||
"""
|
||||
Initialize the connection to the (physical) smart card via a given reader
|
||||
"""
|
||||
|
||||
# See which readers are available
|
||||
readers = smartcard.System.listReaders()
|
||||
if len(readers) <= readernum:
|
||||
logging.error("Invalid number of reader '%u' (only %u available)",
|
||||
readernum, len(readers))
|
||||
sys.exit()
|
||||
|
||||
# Connect to the reader and its card
|
||||
# XXX this is a workaround, see on sourceforge bug #3083254
|
||||
# should better use
|
||||
# self.reader = smartcard.System.readers()[readernum]
|
||||
self.reader = readers[readernum]
|
||||
try:
|
||||
self.session = smartcard.Session(self.reader)
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error connecting to card: %s", e.message)
|
||||
sys.exit()
|
||||
|
||||
logging.info("Connected to card in '%s'", self.reader)
|
||||
|
||||
atexit.register(self.cleanup)
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Close the connection to the physical card
|
||||
"""
|
||||
try:
|
||||
self.session.close()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.warning("Error disconnecting from card: %s", e.message)
|
||||
|
||||
def getATR(self):
|
||||
# when powerDown has been called, fetching the ATR will throw an error.
|
||||
# In this case we must try to reconnect (and then get the ATR).
|
||||
try:
|
||||
atr = self.session.getATR()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
try:
|
||||
# Try to reconnect to the card
|
||||
self.session.close()
|
||||
self.session = smartcard.Session(self.reader)
|
||||
atr = self.session.getATR()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error getting ATR: %s", e.message)
|
||||
sys.exit()
|
||||
|
||||
return "".join([chr(b) for b in atr])
|
||||
|
||||
def powerUp(self):
|
||||
# When powerUp is called multiple times the session is valid (and the
|
||||
# card is implicitly powered) we can check for an ATR. But when
|
||||
# powerDown has been called, the session gets lost. In this case we
|
||||
# must try to reconnect (and power the card).
|
||||
try:
|
||||
self.session.getATR()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
try:
|
||||
self.session = smartcard.Session(self.reader)
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error connecting to card: %s", e.message)
|
||||
sys.exit()
|
||||
|
||||
def powerDown(self):
|
||||
# There is no power down in the session context so we simply
|
||||
# disconnect, which should implicitly power down the card.
|
||||
try:
|
||||
self.session.close()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error disconnecting from card: %s", str(e))
|
||||
sys.exit()
|
||||
|
||||
def execute(self, msg):
|
||||
# sendCommandAPDU() expects a list of APDU bytes
|
||||
apdu = map(ord, msg)
|
||||
|
||||
try:
|
||||
rapdu, sw1, sw2 = self.session.sendCommandAPDU(apdu)
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error transmitting APDU: %s", str(e))
|
||||
sys.exit()
|
||||
|
||||
# XXX this is a workaround, see on sourceforge bug #3083586
|
||||
# should better use
|
||||
# rapdu = rapdu + [sw1, sw2]
|
||||
if rapdu[-2:] == [sw1, sw2]:
|
||||
pass
|
||||
else:
|
||||
rapdu = rapdu + [sw1, sw2]
|
||||
|
||||
# return the response APDU as string
|
||||
return "".join([chr(b) for b in rapdu])
|
||||
|
||||
|
||||
class NPAOS(Iso7816OS):
|
||||
def __init__(self, mf, sam, ins2handler=None, maxle=MAX_EXTENDED_LE, ef_cardsecurity=None, ef_cardaccess=None, ca_key=None, cvca=None, disable_checks=False, esign_key=None, esign_ca_cert=None, esign_cert=None):
|
||||
Iso7816OS.__init__(self, mf, sam, ins2handler, maxle)
|
||||
@@ -685,6 +580,7 @@ class VirtualICC(object):
|
||||
elif card_type == "cryptoflex":
|
||||
self.os = CryptoflexOS(MF, SAM)
|
||||
elif card_type == "relay":
|
||||
from virtualsmartcard.cards.Relay import RelayOS
|
||||
self.os = RelayOS(readernum)
|
||||
elif card_type == "handler_test":
|
||||
self.os = HandlerTestOS()
|
||||
|
||||
126
virtualsmartcard/src/vpicc/virtualsmartcard/cards/Relay.py
Normal file
126
virtualsmartcard/src/vpicc/virtualsmartcard/cards/Relay.py
Normal file
@@ -0,0 +1,126 @@
|
||||
#
|
||||
# Copyright (C) 2015 Frank Morgner
|
||||
#
|
||||
# This file is part of virtualsmartcard.
|
||||
#
|
||||
# virtualsmartcard 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 3 of the License, or (at your option) any
|
||||
# later version.
|
||||
#
|
||||
# virtualsmartcard 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
|
||||
# virtualsmartcard. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from virtualsmartcard.VirtualSmartcard import SmartcardOS
|
||||
import smartcard, logging
|
||||
|
||||
|
||||
class RelayOS(SmartcardOS):
|
||||
"""
|
||||
This class implements relaying of a (physical) smartcard. The RelayOS
|
||||
forwards the command APDUs received from the vpcd to the real smartcard via
|
||||
an actual smart card reader and sends the responses back to the vpcd.
|
||||
This class can be used to implement relay or MitM attacks.
|
||||
"""
|
||||
def __init__(self, readernum):
|
||||
"""
|
||||
Initialize the connection to the (physical) smart card via a given reader
|
||||
"""
|
||||
|
||||
# See which readers are available
|
||||
readers = smartcard.System.listReaders()
|
||||
if len(readers) <= readernum:
|
||||
logging.error("Invalid number of reader '%u' (only %u available)",
|
||||
readernum, len(readers))
|
||||
sys.exit()
|
||||
|
||||
# Connect to the reader and its card
|
||||
# XXX this is a workaround, see on sourceforge bug #3083254
|
||||
# should better use
|
||||
# self.reader = smartcard.System.readers()[readernum]
|
||||
self.reader = readers[readernum]
|
||||
try:
|
||||
self.session = smartcard.Session(self.reader)
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error connecting to card: %s", e.message)
|
||||
sys.exit()
|
||||
|
||||
logging.info("Connected to card in '%s'", self.reader)
|
||||
|
||||
atexit.register(self.cleanup)
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Close the connection to the physical card
|
||||
"""
|
||||
try:
|
||||
self.session.close()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.warning("Error disconnecting from card: %s", e.message)
|
||||
|
||||
def getATR(self):
|
||||
# when powerDown has been called, fetching the ATR will throw an error.
|
||||
# In this case we must try to reconnect (and then get the ATR).
|
||||
try:
|
||||
atr = self.session.getATR()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
try:
|
||||
# Try to reconnect to the card
|
||||
self.session.close()
|
||||
self.session = smartcard.Session(self.reader)
|
||||
atr = self.session.getATR()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error getting ATR: %s", e.message)
|
||||
sys.exit()
|
||||
|
||||
return "".join([chr(b) for b in atr])
|
||||
|
||||
def powerUp(self):
|
||||
# When powerUp is called multiple times the session is valid (and the
|
||||
# card is implicitly powered) we can check for an ATR. But when
|
||||
# powerDown has been called, the session gets lost. In this case we
|
||||
# must try to reconnect (and power the card).
|
||||
try:
|
||||
self.session.getATR()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
try:
|
||||
self.session = smartcard.Session(self.reader)
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error connecting to card: %s", e.message)
|
||||
sys.exit()
|
||||
|
||||
def powerDown(self):
|
||||
# There is no power down in the session context so we simply
|
||||
# disconnect, which should implicitly power down the card.
|
||||
try:
|
||||
self.session.close()
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error disconnecting from card: %s", str(e))
|
||||
sys.exit()
|
||||
|
||||
def execute(self, msg):
|
||||
# sendCommandAPDU() expects a list of APDU bytes
|
||||
apdu = map(ord, msg)
|
||||
|
||||
try:
|
||||
rapdu, sw1, sw2 = self.session.sendCommandAPDU(apdu)
|
||||
except smartcard.Exceptions.CardConnectionException as e:
|
||||
logging.error("Error transmitting APDU: %s", str(e))
|
||||
sys.exit()
|
||||
|
||||
# XXX this is a workaround, see on sourceforge bug #3083586
|
||||
# should better use
|
||||
# rapdu = rapdu + [sw1, sw2]
|
||||
if rapdu[-2:] == [sw1, sw2]:
|
||||
pass
|
||||
else:
|
||||
rapdu = rapdu + [sw1, sw2]
|
||||
|
||||
# return the response APDU as string
|
||||
return "".join([chr(b) for b in rapdu])
|
||||
Reference in New Issue
Block a user