def test_load_card_from_file(self): self.card_generator.generateCard() self.card_generator.saveCard(self.filename) local_generator = CardGenerator(self.card_type) local_generator.password = self.card_generator.password local_generator.loadCard(self.filename) mf, sam = local_generator.getCard() self.assertIsNotNone(mf) self.assertIsNotNone(sam) os.unlink(self.filename)
def test_load_card_from_file(self): self.card_generator.generateCard() self.card_generator.saveCard(self.filename) local_generator= CardGenerator(self.card_type) local_generator.password = self.card_generator.password local_generator.loadCard(self.filename) mf, sam = local_generator.getCard() self.assertIsNotNone(mf) self.assertIsNotNone(sam) os.unlink(self.filename)
class ISO7816GeneratorTest(unittest.TestCase): card_type = 'iso7816' def setUp(self): self.filename = tempfile.mktemp() self.card_generator = CardGenerator(self.card_type) self.card_generator.password = "******" def test_card_creation(self): self.card_generator.generateCard() self.card_generator.saveCard(self.filename) mf, sam = self.card_generator.getCard() self.assertIsNotNone(mf) self.assertIsNotNone(sam) os.unlink(self.filename) def test_load_card_from_file(self): self.card_generator.generateCard() self.card_generator.saveCard(self.filename) local_generator = CardGenerator(self.card_type) local_generator.password = self.card_generator.password local_generator.loadCard(self.filename) mf, sam = local_generator.getCard() self.assertIsNotNone(mf) self.assertIsNotNone(sam) os.unlink(self.filename) def test_load_nonexistent_file(self): with self.assertRaises(anydbm.error): self.card_generator.loadCard(self.filename) def test_get_and_set_card(self): self.card_generator.generateCard() mf, sam = self.card_generator.getCard() local_generator = CardGenerator(self.card_type) local_generator.setCard(mf, sam)
class ISO7816GeneratorTest(unittest.TestCase): card_type = 'iso7816' def setUp(self): self.filename = tempfile.mktemp() self.card_generator = CardGenerator(self.card_type) self.card_generator.password = "******" def test_card_creation(self): self.card_generator.generateCard() self.card_generator.saveCard(self.filename) mf, sam = self.card_generator.getCard() self.assertIsNotNone(mf) self.assertIsNotNone(sam) os.unlink(self.filename) def test_load_card_from_file(self): self.card_generator.generateCard() self.card_generator.saveCard(self.filename) local_generator= CardGenerator(self.card_type) local_generator.password = self.card_generator.password local_generator.loadCard(self.filename) mf, sam = local_generator.getCard() self.assertIsNotNone(mf) self.assertIsNotNone(sam) os.unlink(self.filename) def test_load_nonexistent_file(self): with self.assertRaises(anydbm.error): self.card_generator.loadCard(self.filename) def test_get_and_set_card(self): self.card_generator.generateCard() mf, sam = self.card_generator.getCard() local_generator= CardGenerator(self.card_type) local_generator.setCard(mf, sam)
class VirtualICC(object): """ This class is responsible for maintaining the communication of the virtual PCD and the emulated smartcard. vpicc and vpcd communicate via a socket. The vpcd sends command APDUs (which it receives from an application) to the vicc. The vicc passes these CAPDUs on to an emulated smartcard, which produces a response APDU. This RAPDU is then passed back by the vicc to the vpcd, which forwards it to the application. """ def __init__(self, filename, card_type, host, port, lenlen=3, readernum=None, ef_cardsecurity=None, ef_cardaccess=None, ca_key=None, cvca=None, disable_checks=False): from os.path import exists logging.basicConfig(level = logging.INFO, format = "%(asctime)s [%(levelname)s] %(message)s", datefmt = "%d.%m.%Y %H:%M:%S") self.filename = None self.cardGenerator = CardGenerator(card_type) #If a filename is specified, try to load the card from disk if filename != None: self.filename = filename if exists(filename): self.cardGenerator.loadCard(self.filename) else: logging.info("Creating new card which will be saved in %s.", self.filename) MF, SAM = self.cardGenerator.getCard() #Generate an OS object of the correct card_type if card_type == "iso7816" or card_type == "ePass": self.os = Iso7816OS(MF, SAM) elif card_type == "nPA": self.os = NPAOS(MF, SAM, ef_cardsecurity=ef_cardsecurity, ef_cardaccess=ef_cardaccess, ca_key=ca_key, cvca=cvca, disable_checks=disable_checks) elif card_type == "cryptoflex": self.os = CryptoflexOS(MF, SAM) elif card_type == "relay": self.os = RelayOS(readernum) else: logging.warning("Unknown cardtype %s. Will use standard card_type (ISO 7816)", card_type) card_type = "iso7816" self.os = Iso7816OS(MF, SAM) self.type = card_type #Connect to the VPCD try: self.sock = self.connectToPort(host, port) self.sock.settimeout(None) except socket.error as e: logging.error("Failed to open socket: %s", str(e)) logging.error("Is pcscd running at %s? Is vpcd loaded? Is a firewall blocking port %u?", host, port) sys.exit() self.lenlen = lenlen logging.info("Connected to virtual PCD at %s:%u", host, port) signal.signal(signal.SIGINT, self.signalHandler) atexit.register(self.stop) def signalHandler(self, sig=None, frame=None): """Basically this signal handler just surpresses a traceback from being printed when the user presses crtl-c""" sys.exit() @staticmethod def connectToPort(host, port): """ Open a connection to a given host on a given port. """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) return sock def __sendToVPICC(self, msg): """ Send a message to the vpcd """ #size = inttostring(len(msg), self.lenlen) self.sock.send(struct.pack('!H', len(msg)) + msg) def __recvFromVPICC(self): """ Receive a message from the vpcd """ # receive message size sizestr = self.sock.recv(_Csizeof_short) if len(sizestr) == 0: logging.info("Virtual PCD shut down") sys.exit() size = struct.unpack('!H', sizestr)[0] # receive and return message if size: msg = self.sock.recv(size) if len(msg) == 0: logging.info("Virtual PCD shut down") else: msg = None return size, msg def run(self): """ Main loop of the vpicc. Receives command APDUs via a socket from the vpcd, dispatches them to the emulated smartcard and sends the resulting respsonse APDU back to the vpcd. """ while True : (size, msg) = self.__recvFromVPICC() if not size: logging.warning("Error in communication protocol (missing size parameter)") elif size == VPCD_CTRL_LEN: if msg == chr(VPCD_CTRL_OFF): logging.info("Power Down") self.os.powerDown() elif msg == chr(VPCD_CTRL_ON): logging.info("Power Up") self.os.powerUp() elif msg == chr(VPCD_CTRL_RESET): logging.info("Reset") self.os.reset() elif msg == chr(VPCD_CTRL_ATR): self.__sendToVPICC(self.os.getATR()) else: logging.warning("unknown control command") else: if size != len(msg): logging.warning("Expected %u bytes, but received only %u", size, len(msg)) answer = self.os.execute(msg) logging.info("Response APDU (%d Bytes):\n%s\n", len(answer), hexdump(answer)) self.__sendToVPICC(answer) def stop(self): self.sock.close() if self.filename != None: self.cardGenerator.setCard(self.os.mf, self.os.SAM) self.cardGenerator.saveCard(self.filename)
class VirtualICC(object): """ This class is responsible for maintaining the communication of the virtual PCD and the emulated smartcard. vpicc and vpcd communicate via a socket. The vpcd sends command APDUs (which it receives from an application) to the vicc. The vicc passes these CAPDUs on to an emulated smartcard, which produces a response APDU. This RAPDU is then passed back by the vicc to the vpcd, which forwards it to the application. """ def __init__(self, filename, datasetfile, card_type, host, port, readernum=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): from os.path import exists logging.basicConfig(level = logginglevel, format = "%(asctime)s [%(levelname)s] %(message)s", datefmt = "%d.%m.%Y %H:%M:%S") self.filename = None self.cardGenerator = CardGenerator(card_type) #If a filename is specified, try to load the card from disk if filename != None: self.filename = filename if exists(filename): self.cardGenerator.loadCard(self.filename) else: logging.info("Creating new card which will be saved in %s.", self.filename) #If a dataset file is specified, read the card's data groups from disk if datasetfile != None: if exists(datasetfile): logging.info("Reading Data Groups from file %s.", datasetfile) self.cardGenerator.readDatagroups(datasetfile) MF, SAM = self.cardGenerator.getCard() #Generate an OS object of the correct card_type if card_type == "iso7816" or card_type == "ePass": self.os = Iso7816OS(MF, SAM) elif card_type == "nPA": from virtualsmartcard.cards.nPA import NPAOS self.os = NPAOS(MF, SAM, ef_cardsecurity=ef_cardsecurity, ef_cardaccess=ef_cardaccess, ca_key=ca_key, cvca=cvca, disable_checks=disable_checks, esign_key=esign_key, esign_ca_cert=esign_ca_cert, esign_cert=esign_cert) elif card_type == "cryptoflex": from virtualsmartcard.cards.cryptoflex import CryptoflexOS self.os = CryptoflexOS(MF, SAM) elif card_type == "relay": from virtualsmartcard.cards.Relay import RelayOS self.os = RelayOS(readernum) elif card_type == "handler_test": from virtualsmartcard.cards.HandlerTest import HandlerTestOS self.os = HandlerTestOS() else: logging.warning("Unknown cardtype %s. Will use standard card_type (ISO 7816)", card_type) card_type = "iso7816" self.os = Iso7816OS(MF, SAM) self.type = card_type #Connect to the VPCD self.host = host self.port = port if host: # use normal connection mode try: self.sock = self.connectToPort(host, port) self.sock.settimeout(None) self.server_sock = None except socket.error as e: logging.error("Failed to open socket: %s", str(e)) logging.error("Is pcscd running at %s? Is vpcd loaded? Is a firewall blocking port %u?", host, port) sys.exit() else: # use reversed connection mode try: (self.sock, self.server_sock, host) = self.openPort(port) self.sock.settimeout(None) except socket.error as e: logging.error("Failed to open socket: %s", str(e)) logging.error("Is pcscd running? Is vpcd loaded and in reversed connection mode? Is a firewall blocking port %u?", port) sys.exit() logging.info("Connected to virtual PCD at %s:%u", host, port) signal.signal(signal.SIGINT, self.signalHandler) atexit.register(self.stop) def signalHandler(self, sig=None, frame=None): """Basically this signal handler just surpresses a traceback from being printed when the user presses crtl-c""" sys.exit() @staticmethod def connectToPort(host, port): """ Open a connection to a given host on a given port. """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) return sock @staticmethod def openPort(port): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('', port)) server_socket.listen(0) logging.info("Waiting for vpcd on port " + str(port)) (client_socket, address) = server_socket.accept() return (client_socket, server_socket, address[0]) def __sendToVPICC(self, msg): """ Send a message to the vpcd """ self.sock.sendall(struct.pack('!H', len(msg)) + msg) def __recvFromVPICC(self): """ Receive a message from the vpcd """ # receive message size sizestr = self.sock.recv(_Csizeof_short) if len(sizestr) == 0: logging.info("Virtual PCD shut down") raise socket.error size = struct.unpack('!H', sizestr)[0] # receive and return message if size: msg = self.sock.recv(size) if len(msg) == 0: logging.info("Virtual PCD shut down") raise socket.error else: msg = None return size, msg def run(self): """ Main loop of the vpicc. Receives command APDUs via a socket from the vpcd, dispatches them to the emulated smartcard and sends the resulting respsonse APDU back to the vpcd. """ while True : try: (size, msg) = self.__recvFromVPICC() except socket.error as e: if not self.host: logging.info("Waiting for vpcd on port " + str(self.port)) (self.sock, address) = self.server_sock.accept() continue else: sys.exit() if not size: logging.warning("Error in communication protocol (missing size parameter)") elif size == VPCD_CTRL_LEN: if msg == chr(VPCD_CTRL_OFF): logging.info("Power Down") self.os.powerDown() elif msg == chr(VPCD_CTRL_ON): logging.info("Power Up") self.os.powerUp() elif msg == chr(VPCD_CTRL_RESET): logging.info("Reset") self.os.reset() elif msg == chr(VPCD_CTRL_ATR): self.__sendToVPICC(self.os.getATR()) else: logging.warning("unknown control command") else: if size != len(msg): logging.warning("Expected %u bytes, but received only %u", size, len(msg)) answer = self.os.execute(msg) logging.info("Response APDU (%d Bytes):\n%s\n", len(answer), hexdump(answer)) self.__sendToVPICC(answer) def stop(self): self.sock.close() if self.server_sock: self.server_sock.close() if self.filename != None: self.cardGenerator.setCard(self.os.mf, self.os.SAM) self.cardGenerator.saveCard(self.filename)
class VirtualICC(object): """ This class is responsible for maintaining the communication of the virtual PCD and the emulated smartcard. vpicc and vpcd communicate via a socket. The vpcd sends command APDUs (which it receives from an application) to the vicc. The vicc passes these CAPDUs on to an emulated smartcard, which produces a response APDU. This RAPDU is then passed back by the vicc to the vpcd, which forwards it to the application. """ def __init__(self, filename, datasetfile, card_type, host, port, readernum=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): from os.path import exists logging.basicConfig(level=logginglevel, format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%d.%m.%Y %H:%M:%S") self.filename = None self.cardGenerator = CardGenerator(card_type) # If a filename is specified, try to load the card from disk if filename is not None: self.filename = filename if exists(filename): self.cardGenerator.loadCard(self.filename) else: logging.info("Creating new card which will be saved in %s.", self.filename) # If a dataset file is specified, read the card's data groups from disk if datasetfile is not None: if exists(datasetfile): logging.info("Reading Data Groups from file %s.", datasetfile) self.cardGenerator.readDatagroups(datasetfile) MF, SAM = self.cardGenerator.getCard() # Generate an OS object of the correct card_type if card_type == "iso7816" or card_type == "ePass": self.os = Iso7816OS(MF, SAM) elif card_type == "nPA": from virtualsmartcard.cards.nPA import NPAOS self.os = NPAOS(MF, SAM, ef_cardsecurity=ef_cardsecurity, ef_cardaccess=ef_cardaccess, ca_key=ca_key, cvca=cvca, disable_checks=disable_checks, esign_key=esign_key, esign_ca_cert=esign_ca_cert, esign_cert=esign_cert) elif card_type == "cryptoflex": from virtualsmartcard.cards.cryptoflex import CryptoflexOS self.os = CryptoflexOS(MF, SAM) elif card_type == "relay": from virtualsmartcard.cards.Relay import RelayOS self.os = RelayOS(readernum) elif card_type == "handler_test": from virtualsmartcard.cards.HandlerTest import HandlerTestOS self.os = HandlerTestOS() else: logging.warning("Unknown cardtype %s. Will use standard card_type \ (ISO 7816)", card_type) card_type = "iso7816" self.os = Iso7816OS(MF, SAM) self.type = card_type # Connect to the VPCD self.host = host self.port = port if host: # use normal connection mode try: self.sock = self.connectToPort(host, port) self.sock.settimeout(None) self.server_sock = None except socket.error as e: logging.error("Failed to open socket: %s", str(e)) logging.error("Is pcscd running at %s? Is vpcd loaded? Is a \ firewall blocking port %u?", host, port) sys.exit() else: # use reversed connection mode try: local_ip = [(s.connect(('8.8.8.8', 53)), s.getsockname()[0], s.close()) for s in [socket.socket(socket.AF_INET, socket.SOCK_DGRAM)]][0][1] custom_url = 'vicc://%s:%d' % (local_ip, port) print('VICC hostname: %s' % local_ip); print('VICC port: %d' % port) print('On your NFC phone with the Android Smart Card Emulator app scan this code:') try: import qrcode qr = qrcode.QRCode() qr.add_data(custom_url) qr.print_ascii() except ImportError: print('https://api.qrserver.com/v1/create-qr-code/?data=%s' % custom_url) (self.sock, self.server_sock, host) = self.openPort(port) self.sock.settimeout(None) except socket.error as e: logging.error("Failed to open socket: %s", str(e)) logging.error("Is pcscd running? Is vpcd loaded and in \ reversed connection mode? Is a firewall \ blocking port %u?", port) sys.exit() logging.info("Connected to virtual PCD at %s:%u", host, port) signal.signal(signal.SIGINT, self.signalHandler) atexit.register(self.stop) def signalHandler(self, sig=None, frame=None): """Basically this signal handler just surpresses a traceback from being printed when the user presses crtl-c""" sys.exit() @staticmethod def connectToPort(host, port): """ Open a connection to a given host on a given port. """ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((host, port)) return sock @staticmethod def openPort(port): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(('', port)) server_socket.listen(0) logging.info("Waiting for vpcd on port " + str(port)) (client_socket, address) = server_socket.accept() return (client_socket, server_socket, address[0]) def __sendToVPICC(self, msg): """ Send a message to the vpcd """ self.sock.sendall(struct.pack('!H', len(msg)) + msg) def __recvFromVPICC(self): """ Receive a message from the vpcd """ # receive message size sizestr = self.sock.recv(_Csizeof_short) if len(sizestr) == 0: logging.info("Virtual PCD shut down") raise socket.error size = struct.unpack('!H', sizestr)[0] # receive and return message if size: msg = self.sock.recv(size) if len(msg) == 0: logging.info("Virtual PCD shut down") raise socket.error else: msg = None return size, msg def run(self): """ Main loop of the vpicc. Receives command APDUs via a socket from the vpcd, dispatches them to the emulated smartcard and sends the resulting respsonse APDU back to the vpcd. """ while True: try: (size, msg) = self.__recvFromVPICC() except socket.error as e: if not self.host: logging.info("Waiting for vpcd on port " + str(self.port)) (self.sock, address) = self.server_sock.accept() continue else: sys.exit() if not size: logging.warning("Error in communication protocol (missing \ size parameter)") elif size == VPCD_CTRL_LEN: if msg == chr(VPCD_CTRL_OFF): logging.info("Power Down") self.os.powerDown() elif msg == chr(VPCD_CTRL_ON): logging.info("Power Up") self.os.powerUp() elif msg == chr(VPCD_CTRL_RESET): logging.info("Reset") self.os.reset() elif msg == chr(VPCD_CTRL_ATR): self.__sendToVPICC(self.os.getATR()) else: logging.warning("unknown control command") else: if size != len(msg): logging.warning("Expected %u bytes, but received only %u", size, len(msg)) answer = self.os.execute(msg) logging.info("Response APDU (%d Bytes):\n%s\n", len(answer), hexdump(answer)) self.__sendToVPICC(answer) def stop(self): self.sock.close() if self.server_sock: self.server_sock.close() if self.filename is not None: self.cardGenerator.setCard(self.os.mf, self.os.SAM) self.cardGenerator.saveCard(self.filename)