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 \
|
vpicccards_PYTHON = virtualsmartcard/cards/__init__.py \
|
||||||
virtualsmartcard/cards/ePass.py \
|
virtualsmartcard/cards/ePass.py \
|
||||||
virtualsmartcard/cards/nPA.py \
|
virtualsmartcard/cards/nPA.py \
|
||||||
|
virtualsmartcard/cards/Relay.py \
|
||||||
virtualsmartcard/cards/cryptoflex.py
|
virtualsmartcard/cards/cryptoflex.py
|
||||||
|
|
||||||
do_subst = $(SED) \
|
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.utils import C_APDU, R_APDU, hexdump, inttostring
|
||||||
from virtualsmartcard.CardGenerator import CardGenerator
|
from virtualsmartcard.CardGenerator import CardGenerator
|
||||||
|
|
||||||
import socket, struct, sys, signal, atexit, smartcard, logging
|
import socket, struct, sys, signal, atexit, logging
|
||||||
|
|
||||||
|
|
||||||
class SmartcardOS(object):
|
class SmartcardOS(object):
|
||||||
@@ -397,111 +397,6 @@ class CryptoflexOS(Iso7816OS):
|
|||||||
return r
|
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):
|
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):
|
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)
|
Iso7816OS.__init__(self, mf, sam, ins2handler, maxle)
|
||||||
@@ -685,6 +580,7 @@ class VirtualICC(object):
|
|||||||
elif card_type == "cryptoflex":
|
elif card_type == "cryptoflex":
|
||||||
self.os = CryptoflexOS(MF, SAM)
|
self.os = CryptoflexOS(MF, SAM)
|
||||||
elif card_type == "relay":
|
elif card_type == "relay":
|
||||||
|
from virtualsmartcard.cards.Relay import RelayOS
|
||||||
self.os = RelayOS(readernum)
|
self.os = RelayOS(readernum)
|
||||||
elif card_type == "handler_test":
|
elif card_type == "handler_test":
|
||||||
self.os = HandlerTestOS()
|
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