Merge pull request #181 from betawave/relay-mitm-enhancement

basic Man-in-the-Middle extension to the Relay-Card
This commit is contained in:
Frank Morgner
2020-10-27 11:06:05 +01:00
committed by GitHub
5 changed files with 64 additions and 4 deletions

View File

@@ -24,6 +24,7 @@ vpicccards_PYTHON = virtualsmartcard/cards/__init__.py \
virtualsmartcard/cards/ePass.py \
virtualsmartcard/cards/nPA.py \
virtualsmartcard/cards/Relay.py \
virtualsmartcard/cards/RelayMiddleman.py \
virtualsmartcard/cards/cryptoflex.py
do_subst = $(SED) \

View File

@@ -66,6 +66,10 @@ relay.add_argument("--reader",
type=int,
default=0,
help="number of the reader containing the card to be relayed (default: %(default)s)")
relay.add_argument("--mitm",
action="store",
type=str,
help="relative path to a file containing a Man-in-the-Middle class that is supposed to be used with the relay")
npa = parser.add_argument_group('Emulation of German identity card (`--type=nPA`)')
npa.add_argument("--ef-cardaccess",
@@ -153,7 +157,7 @@ else:
hostname = args.hostname
vicc = VirtualICC(args.datasetfile, args.type, hostname, args.port,
readernum=args.reader, ef_cardaccess=ef_cardaccess_data,
readernum=args.reader, mitmPath=args.mitm, ef_cardaccess=ef_cardaccess_data,
ef_cardsecurity=ef_cardsecurity_data, ca_key=ca_key_data, cvca=cvca,
disable_checks=args.disable_ta_checks, esign_ca_cert=esign_ca_cert,
esign_cert=esign_cert, logginglevel=logginglevel)

View File

@@ -370,6 +370,30 @@ class Iso7816OS(SmartcardOS):
self.mf.current = self.mf
def loadMitMFromPath(path: str):
from importlib import import_module
from pathlib import Path
def onNth(tup,ind,func):
start = tup[0:ind] + (func(tup[ind]),)
return start if ind + 1 == 0 else start + tup[ind+1:]
def pathToModuleName(path):
return ".".join(onNth(Path(path).parts,-1,lambda fName : str(Path(fName).stem)))
mitmModule = import_module(pathToModuleName(path))
# Sanity Checks
if not getattr(mitmModule,"get_MitM",None):
raise ValueError("The provided module does not contain a 'get_MitM' method.")
mitm = mitmModule.get_MitM()
if not getattr(mitm,"handleInPDU",None):
raise ValueError("The produced MitM has no 'handleInPDU' method.")
if not getattr(mitm,"handleOutPDU",None):
raise ValueError("The produced MitM has no 'handleOutPDU' method.")
return mitm
# sizeof(int) taken from asizof-package {{{
_Csizeof_short = len(struct.pack('h', 0))
# }}}
@@ -393,7 +417,7 @@ class VirtualICC(object):
"""
def __init__(self, datasetfile, card_type, host, port,
readernum=None, ef_cardsecurity=None, ef_cardaccess=None,
readernum=None, mitmPath=None, ef_cardsecurity=None, ef_cardaccess=None,
ca_key=None, cvca=None, disable_checks=False, esign_key=None,
esign_ca_cert=None, esign_cert=None,
logginglevel=logging.INFO):
@@ -429,7 +453,9 @@ class VirtualICC(object):
self.os = CryptoflexOS(MF, SAM)
elif card_type == "relay":
from virtualsmartcard.cards.Relay import RelayOS
self.os = RelayOS(readernum)
from virtualsmartcard.cards.RelayMiddleman import RelayMiddleman
mitm = loadMitMFromPath(mitmPath) if mitmPath else RelayMiddleman()
self.os = RelayOS(readernum,mitm=mitm)
elif card_type == "handler_test":
from virtualsmartcard.cards.HandlerTest import HandlerTestOS
self.os = HandlerTestOS()

View File

@@ -22,6 +22,7 @@ import logging
import smartcard
import sys
from virtualsmartcard.VirtualSmartcard import SmartcardOS
from virtualsmartcard.cards.RelayMiddleman import RelayMiddleman
class RelayOS(SmartcardOS):
@@ -31,7 +32,7 @@ class RelayOS(SmartcardOS):
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):
def __init__(self, readernum, mitm=RelayMiddleman()):
"""
Initialize the connection to the (physical) smart card via a given
reader
@@ -57,6 +58,8 @@ class RelayOS(SmartcardOS):
logging.info("Connected to card in '%s'", self.reader)
self.mitm = mitm
atexit.register(self.cleanup)
def cleanup(self):
@@ -119,6 +122,8 @@ class RelayOS(SmartcardOS):
else:
apdu = list(msg)
apdu = self.mitm.handleInPDU(apdu)
try:
rapdu, sw1, sw2 = self.session.sendCommandAPDU(apdu)
except smartcard.Exceptions.CardConnectionException as e:
@@ -133,5 +138,7 @@ class RelayOS(SmartcardOS):
else:
rapdu = rapdu + [sw1, sw2]
rapdu = self.mitm.handleOutPDU(rapdu)
# return the response APDU as string
return "".join(map(chr, rapdu))

View File

@@ -0,0 +1,22 @@
class RelayMiddleman(object):
"""
The RelayMiddleman class serves as a base from which a user might derive
their own relay middle man class. This base class implements the simplest
Man-in-the-Middle: the NoOp.
"""
def handleInPDU(self, inPDU: bytes):
"""
This method is called on each PDU that is fed into the realy (vdpu -> vicc).
It may be overwritten to modify the packages send from the terminal to the
real smart card.
"""
return inPDU
def handleOutPDU(self, outPDU: bytes):
"""
This method is called on each PDU that is produced by the relay (vicc -> vdpu).
It may be overwritten to modify the packages send from the real smart card to the
terminal.
"""
return outPDU