diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py b/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py index d0af41b..fd89f6c 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/SEutils.py @@ -410,7 +410,7 @@ class Security_Environment(object): # if expected != "": # raise SwError(SW["ERR_SECMESSOBJECTSMISSING"]) - if isinstance(le, str): + if isinstance(le, bytes): # FIXME: C_APDU only handles le with strings of length 1. # Better patch utils.py to support extended length apdus le_int = stringtoint(le) @@ -702,23 +702,23 @@ class Security_Environment(object): # Encode keys if cipher == "RSA": # Public key - n = str(PublicKey.__getstate__()['n']) - e = str(PublicKey.__getstate__()['e']) + n = inttostring(PublicKey.__getstate__()['n']) + e = inttostring(PublicKey.__getstate__()['e']) pk = ((0x81, len(n), n), (0x82, len(e), e)) result = bertlv_pack(pk) # Private key d = PublicKey.__getstate__()['d'] elif cipher == "DSA": # DSAParams - p = str(PublicKey.__getstate__()['p']) - q = str(PublicKey.__getstate__()['q']) - g = str(PublicKey.__getstate__()['g']) + p = inttostring(PublicKey.__getstate__()['p']) + q = inttostring(PublicKey.__getstate__()['q']) + g = inttostring(PublicKey.__getstate__()['g']) # Public key - y = str(PublicKey.__getstate__()['y']) + y = inttostring(PublicKey.__getstate__()['y']) pk = ((0x81, len(p), p), (0x82, len(q), q), (0x83, len(g), g), (0x84, len(y), y)) # Private key - x = str(PublicKey.__getstate__()['x']) + x = inttostring(PublicKey.__getstate__()['x']) # Add more algorithms here # elif cipher = "ECDSA": else: diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardFilesystem.py b/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardFilesystem.py index af6a7c5..3b4b6b5 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardFilesystem.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/SmartcardFilesystem.py @@ -139,14 +139,14 @@ def write(old, newlist, offsets, datacoding, maxsize=None): while newindex < writenow: if datacoding == DCB["WRITEOR"]: newpiece = inttostring( - ord(result[resultindex]) | ord(new[newindex])) + result[resultindex] | new[newindex]) elif datacoding == DCB["WRITEAND"]: newpiece = inttostring( - ord(result[resultindex]) & ord(new[newindex])) + result[resultindex] & new[newindex]) elif datacoding == DCB["PROPRIETARY"]: # we use it for XOR newpiece = inttostring( - ord(result[resultindex]) ^ ord(new[newindex])) + result[resultindex] ^ new[newindex]) result = (result[0:resultindex] + newpiece + result[resultindex+1:len(result)]) newindex = newindex + 1 @@ -246,7 +246,7 @@ class File(object): simpletlv_data=None, bertlv_data=None, SAM=None, - extra_fci_data=''): + extra_fci_data=b''): """ The constructor is supposed to be involved by creation of a DF or EF. """ @@ -642,12 +642,12 @@ class MF(DF): l += simpletlv_unpack(r.data)[0][1] else: l += len(r.data) - fdm.append("%c\x02%s" % (TAG["BYTES_EXCLUDINGSTRUCTURE"], + fdm.append(b"%c\x02%s" % (TAG["BYTES_EXCLUDINGSTRUCTURE"], inttostring(l, 2, True))) - fdm.append("%c\x02%s" % (TAG["BYTES_INCLUDINGSTRUCTURE"], + fdm.append(b"%c\x02%s" % (TAG["BYTES_INCLUDINGSTRUCTURE"], inttostring(l, 2, True))) l = len(records) - fdm.append("%c\x06%c%c%c%c%s" % (TAG["FILEDISCRIPTORBYTE"], + fdm.append(b"%c\x06%c%c%c%c%s" % (TAG["FILEDISCRIPTORBYTE"], file.filedescriptor, file.datacoding, file.maxrecordsize >> 8, file.maxrecordsize & 0x00ff, @@ -655,10 +655,10 @@ class MF(DF): elif isinstance(file, DF): # TODO number of files == number of data bytes? - fdm.append("%c\x01%c" % (TAG["FILEDISCRIPTORBYTE"], + fdm.append(b"%c\x01%c" % (TAG["FILEDISCRIPTORBYTE"], file.filedescriptor)) if hasattr(file, 'dfname'): - fdm.append("%c%c%s" % (TAG["DFNAME"], len(file.dfname), + fdm.append(b"%c%c%s" % (TAG["DFNAME"], len(file.dfname), file.dfname)) else: @@ -748,6 +748,7 @@ class MF(DF): data = bertlv_pack([(tag, len(fdm), fdm)]) self.current = file + logging.info("Selected %s" % file) return SW["NORMAL"], data @@ -1309,9 +1310,9 @@ class MF(DF): if l >= 3: args["maxrecordsize"] = stringtoint(value[2:]) if l >= 2: - args["datacoding"] = ord(value[1]) + args["datacoding"] = value[1] if l >= 1: - args["filedescriptor"] = ord(value[0]) + args["filedescriptor"] = value[0] def shortfid2args(value, args): s = stringtoint(value) @@ -1323,19 +1324,6 @@ class MF(DF): def unknown(tag, value): logging.debug("unknown tag 0x%x with %r" % (tag, value)) - tag2cmd = { - # TODO support other tags - TAG["FILEDISCRIPTORBYTE"]: 'fdb2args(value, args)', - TAG["FILEIDENTIFIER"]: 'args["fid"] = stringtoint(value)', - TAG["DFNAME"]: 'args["dfname"] = value', - TAG["SHORTFID"]: 'shortfid2args(value, args)', - TAG["LIFECYCLESTATUS"]: 'args["lifecycle"] = ' + \ - 'stringtoint(value)', - TAG["BYTES_EXCLUDINGSTRUCTURE"]: 'args["data"] = bytes(0) ' + \ - '* stringtoint(value)', - TAG["BYTES_INCLUDINGSTRUCTURE"]: 'args["data"] = bytes(0) ' + \ - '* stringtoint(value)', - } fcp_list = tlv_find_tags(bertlv_unpack(data), [TAG["FILECONTROLINFORMATION"], TAG["FILECONTROLPARAMETERS"]]) @@ -1353,9 +1341,23 @@ class MF(DF): T != TAG["FILECONTROLINFORMATION"]): raise ValueError for tag, _, value in tlv_data: - exec(tag2cmd.get(tag, 'unknown(tag, value)') in locals(), - globals()) - + if tag == TAG["FILEDISCRIPTORBYTE"]: + fdb2args(value, args) + elif tag == TAG["FILEIDENTIFIER"]: + args["fid"] = stringtoint(value) + elif tag == TAG["DFNAME"]: + args["dfname"] = value + elif tag == TAG["SHORTFID"]: + shortfid2args(value, args) + elif tag == TAG["LIFECYCLESTATUS"]: + args["lifecycle"] = stringtoint(value) + elif tag == TAG["BYTES_EXCLUDINGSTRUCTURE"]: + args["data"] = b'\x00' * stringtoint(value) + elif tag == TAG["BYTES_INCLUDINGSTRUCTURE"]: + args["data"] = b'\x00' * stringtoint(value) + else: + unknown(tag, value) + print(args) if (args["filedescriptor"] & FDB["DF"]) == FDB["DF"]: # FIXME: data for DF if "data" in args: @@ -1391,6 +1393,7 @@ class MF(DF): file.parent = df df.append(file) self.current = file + logging.info("Created %s" % file) return SW["NORMAL"], b"" @@ -1406,6 +1409,7 @@ class MF(DF): file.parent.content.remove(file) # FIXME: free memory of file and remove its content from the security # device + logging.info("Deleted %s" % file) return SW["NORMAL"], b"" @@ -1738,7 +1742,7 @@ class RecordStructureEF(EF): raise SwError(SW["ERR_INCORRECTPARAMETERS"]) if self.hasFixedRecordSize(): - data = bytes(0)*(self.maxrecordsize) + data + data = b'\x00'*(self.maxrecordsize) + data records = self.records if self.isCyclic(): diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py b/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py index 666da9d..c696dde 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/TLVutils.py @@ -17,7 +17,7 @@ # virtualsmartcard. If not, see . # -from virtualsmartcard.utils import stringtoint +from virtualsmartcard.utils import stringtoint, inttostring TAG = {} TAG["FILECONTROLPARAMETERS"] = 0x62 @@ -93,7 +93,7 @@ def tlv_find_tags(tlv_data, tags, num_results=None): if t in tags: results.append(d) else: - if isinstance(v, list): + if isinstance(v, bytes) and not isinstance(v[0], int): find_recursive(v) if num_results is not None and len(results) >= num_results: @@ -119,35 +119,35 @@ def pack(tlv_data, recalculate_length=False): for data in tlv_data: tag, length, value = data[:3] if tag in (0xff, 0x00): - result.append(chr(tag)) + result.append(inttostring(tag)) continue - if not isinstance(value, str): + if not isinstance(value, bytes): value = pack(value, recalculate_length) if recalculate_length: length = len(value) - t = "" + t = b"" while tag > 0: - t = chr(tag & 0xff) + t + t = inttostring(tag & 0xff) + t tag = tag >> 8 if length < 0x7F: - l = chr(length) + l = inttostring(length) else: - l = "" + l = b"" while length > 0: - l = chr(length & 0xff) + l + l = inttostring(length & 0xff) + l length = length >> 8 assert len(l) < 0x7f - l = chr(0x80 | len(l)) + l + l = inttostring(0x80 | len(l)) + l result.append(t) result.append(l) result.append(value) - return "".join(result) + return b"".join(result) def bertlv_pack(data): @@ -158,7 +158,7 @@ def bertlv_pack(data): def unpack(data, with_marks=None, offset=0, include_filler=False): result = [] if isinstance(data, str): - data = map(ord, data) + data = list(map(ord, data)) while len(data) > 0: if data[0] in (0x00, 0xFF): if include_filler: @@ -202,7 +202,7 @@ def bertlv_unpack(data): def simpletlv_pack(tlv_data, recalculate_length=False): - result = "" + result = b"" for tag, length, value in tlv_data: if tag >= 0xff or tag <= 0x00: @@ -216,10 +216,10 @@ def simpletlv_pack(tlv_data, recalculate_length=False): continue if length < 0xff: - result += chr(tag) + chr(length) + value + result += inttostring(tag) + inttostring(length) + value else: - result += chr(tag) + chr(0xff) + chr(length >> 8) + \ - chr(length & 0xff) + value + result += inttostring(tag) + inttostring(0xff) + inttostring(length >> 8) + \ + inttostring(length & 0xff) + value return result @@ -229,7 +229,7 @@ def simpletlv_unpack(data): newvalue).""" result = [] if isinstance(data, str): - data = map(ord, data) + data = list(map(ord, data)) rest = data while rest: tag = rest[0] diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py b/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py index 39f135e..ccd330e 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/VirtualSmartcard.py @@ -23,6 +23,7 @@ import logging import socket import struct import sys +import traceback from virtualsmartcard.ConstantDefinitions import MAX_EXTENDED_LE, MAX_SHORT_LE from virtualsmartcard.SWutils import SwError, SW from virtualsmartcard.SmartcardFilesystem import make_property @@ -282,15 +283,17 @@ class Iso7816OS(SmartcardOS): """ raise SwError(SW["ERR_INSNOTSUPPORTED"]) + logging.info("Command APDU (%d bytes):\n %s", len(msg), + hexdump(msg, indent=2)) + try: c = C_APDU(msg) + logging.debug("%s", str(c)) except ValueError as e: logging.warning(str(e)) return self.formatResult(False, 0, b"", SW["ERR_INCORRECTPARAMETERS"], False) - logging.info("Parsed APDU:\n%s", str(c)) - # Handle Class Byte # {{{ class_byte = c.cla @@ -352,9 +355,8 @@ class Iso7816OS(SmartcardOS): answer = self.formatResult(Iso7816OS.seekable(c.ins), c.effective_Le, result, sw, sm) except SwError as e: + logging.debug(traceback.format_exc().rstrip()) logging.info(e.message) - import traceback - traceback.print_exception(*sys.exc_info()) sw = e.sw result = b"" answer = self.formatResult(False, 0, result, sw, sm) @@ -575,8 +577,8 @@ class VirtualICC(object): size, len(msg)) answer = self.os.execute(msg) - logging.info("Response APDU (%d Bytes):\n%s\n", len(answer), - hexdump(answer)) + logging.info("Response APDU (%d bytes):\n %s\n", len(answer), + hexdump(answer, indent=2)) self.__sendToVPICC(answer) def stop(self): diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/cards/nPA.py b/virtualsmartcard/src/vpicc/virtualsmartcard/cards/nPA.py index aa574c9..6d6a573 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/cards/nPA.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/cards/nPA.py @@ -92,8 +92,8 @@ class NPAOS(Iso7816OS): try: sw, result = self.SAM.protect_result(sw, result) except SwError as e: + logging.debug(traceback.format_exc().rstrip()) logging.info(e.message) - traceback.print_exception(*sys.exc_info()) sw = e.sw result = b"" answer = self.formatResult(False, 0, result, sw, False) diff --git a/virtualsmartcard/src/vpicc/virtualsmartcard/utils.py b/virtualsmartcard/src/vpicc/virtualsmartcard/utils.py index 4f769fe..2c981b7 100644 --- a/virtualsmartcard/src/vpicc/virtualsmartcard/utils.py +++ b/virtualsmartcard/src/vpicc/virtualsmartcard/utils.py @@ -22,10 +22,14 @@ import struct from virtualsmartcard.ConstantDefinitions import MAX_SHORT_LE, MAX_EXTENDED_LE -def stringtoint(str): - if str: - return int(str.encode('hex'), 16) - return 0 +def stringtoint(data): + i = 0 + if data: + if isinstance(data, str): + data = list(map(ord, data)) + for byte in data: + i = (i << 8) + byte + return i def inttostring(i, length=None, len_extendable=False): @@ -61,7 +65,7 @@ def hexdump(data, indent=0, short=False, linelen=16, offset=0): def hexable(data): if isinstance(data, str): - data = map(ord, data) + data = list(map(ord, data)) return " ".join(map("{0:0>2X}".format, data)) def printable(data): @@ -71,7 +75,7 @@ def hexdump(data, indent=0, short=False, linelen=16, offset=0): return "%s (%s)" % (hexable(data), printable(data)) if isinstance(data, str): - data = map(ord, data) + data = list(map(ord, data)) FORMATSTRING = "%04x: %-" + str(linelen*3) + "s %-" + str(linelen) + "s" result = "" (head, tail) = (data[:linelen], data[linelen:]) @@ -199,10 +203,7 @@ class APDU(object): ", ".join(self._format_fields())) if len(self.data) > 0: - result = result + " with %i (0x%02x) bytes of data" % ( - len(self.data), len(self.data) - ) - return result + ":\n" + hexdump(self.data) + return result + ":\n " + hexdump(self.data, indent=2) else: return result