From 299f6ef3aac67fdee4f45921482eb4000cc6dedf Mon Sep 17 00:00:00 2001 From: Niklas Bittner Date: Thu, 16 Jan 2025 04:11:20 +0100 Subject: [PATCH] feat: basic replay functionality --- .vscode/launch.json | 17 +++++ poetry.lock | 68 ++++++++++++-------- pyproject.toml | 6 +- resimulate/__init__.py | 0 resimulate/commands/record.py | 44 +++++++------ resimulate/commands/replay.py | 54 +++++++++++++++- resimulate/exceptions.py | 2 + resimulate/resimulate.py | 20 +++--- resimulate/util/apdu_highlighter.py | 26 ++++++++ resimulate/util/logger.py | 10 ++- resimulate/util/pcsc_link.py | 98 +++++++++++++++++++++++++++++ resimulate/util/tracer.py | 17 +++-- 12 files changed, 296 insertions(+), 66 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 resimulate/__init__.py create mode 100644 resimulate/exceptions.py create mode 100644 resimulate/util/apdu_highlighter.py create mode 100644 resimulate/util/pcsc_link.py diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..e519367 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "reSIMulate: record", + "type": "debugpy", + "request": "launch", + "program": "${workspaceFolder}/resimulate/resimulate.py", + "console": "integratedTerminal", + "args": ["record", "-o test.pkl"], + "justMyCode": false + } + ] +} diff --git a/poetry.lock b/poetry.lock index 3137f0a..2c13936 100644 --- a/poetry.lock +++ b/poetry.lock @@ -558,14 +558,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyosmocom" -version = "0.0.7" +version = "0.0.8" description = "Python implementation of core osmocom utilities / protocols" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pyosmocom-0.0.7-py3-none-any.whl", hash = "sha256:6abcd35b7ecca8e8c5edd1d3f5a508c8692a2084a27aca488a4ff487fad7e317"}, - {file = "pyosmocom-0.0.7.tar.gz", hash = "sha256:d6fcab6234fb5007af5dd4bc676ff29397dc40a53756997e64493e3e335502b4"}, + {file = "pyosmocom-0.0.8-py3-none-any.whl", hash = "sha256:eaa09524bb031b0408ce69dba4ce0f60525c016b8033e92aaa5475483ad5a472"}, + {file = "pyosmocom-0.0.8.tar.gz", hash = "sha256:d008d64d6423dd79980b1e8df4ab751eb68acb48a3e18c976e293d71b50d36f0"}, ] [package.dependencies] @@ -601,29 +601,30 @@ dev = ["build", "flake8", "mypy", "pytest", "twine"] [[package]] name = "pyscard" -version = "2.2.0" +version = "2.2.1" description = "Smartcard module for Python." optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pyscard-2.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05cfa9840b3f4b08769487e4d84b1432d9d913035a3726856329c2648444a6ba"}, - {file = "pyscard-2.2.0-cp310-cp310-win32.whl", hash = "sha256:c363a36a803cd3e6334546d661c0b1375c16ab42600bc4be18ade3ed70eae1a6"}, - {file = "pyscard-2.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:001e760f42d2f9b7b6aba6b83fca67314e925d6df1ded75689c5ef5377f6e701"}, - {file = "pyscard-2.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:51758a04e70d07b233a5d7ed58492007bbbebcb3f47130a638edbe021b82df86"}, - {file = "pyscard-2.2.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a138707d8ef5c53da4e7a86d1e604e2cba42fe92249099a67374624503825326"}, - {file = "pyscard-2.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:45ec2a19cbc40dc56c9831f9979c81617a3a89265b1430708e1c137a82ec5c83"}, - {file = "pyscard-2.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9a3d47a6799efbc8e6124638730a86b705ddecfba92874aec6b79348e764fe8a"}, - {file = "pyscard-2.2.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:fe8625b7cb1be2af0fe5d90d6daabb26a65aeb7d601455446c6a06341a2f0814"}, - {file = "pyscard-2.2.0-cp312-cp312-win32.whl", hash = "sha256:b0b476691652bb641b175d7d345bb27639615c6a5bf140e63a057750aefc1bd9"}, - {file = "pyscard-2.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:9ce06b7007147f7346114274dd20edd0399e9aedbdadcc9cf4d0c867bec1cae1"}, - {file = "pyscard-2.2.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5296c705d2f5b6947f6929a63d55521a380125c0160679b8069a11107c8b94ec"}, - {file = "pyscard-2.2.0-cp313-cp313-win32.whl", hash = "sha256:6cdb99c1d51f625fe246df57b65fad6d834a094fa5efd36d0c40356916c19431"}, - {file = "pyscard-2.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:ff6f2b8ef00b48fa5f1448f0c7d812f677ce98a9994e917500ecf00e3f31dc89"}, - {file = "pyscard-2.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0f23309f4f98ae41c836090c3449d8fb7470c19d57adda2592803e1df668bece"}, - {file = "pyscard-2.2.0-cp39-cp39-win32.whl", hash = "sha256:5857d60b44bbb074c9b174111fe94af4179b882942e53292de16f0c798f50c5d"}, - {file = "pyscard-2.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:e4e664b1d3b87956104b87094f81a98bdd6ac40986b52d0c40451de1fc98ca49"}, - {file = "pyscard-2.2.0.tar.gz", hash = "sha256:6aa194d4bb295e78a97056dd1d32273cc69ddbe3c852aad60a8578f04017a1bf"}, + {file = "pyscard-2.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e0e85b8a0a316690be7d5b2e85302651f0443db271a8ca77cb09f8a6fdd6ebfa"}, + {file = "pyscard-2.2.1-cp310-cp310-win32.whl", hash = "sha256:fcac209666236bd08d876834f8233046713139490b46a37baa19e4eee959d003"}, + {file = "pyscard-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:4a638bc33d6c6b4a95ac4e7b5eb4426b3e1d0c5b74e018a650294473456b43c3"}, + {file = "pyscard-2.2.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:21b458aef2baaf97a3dc719b7d6d94d9333d5cff703536688ee9881993607328"}, + {file = "pyscard-2.2.1-cp311-cp311-win32.whl", hash = "sha256:4bec90a07e25220a6eeaa2a6d6e45c60ce40b5e0f0c7059f03f16357c01e66a8"}, + {file = "pyscard-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:aa886dda9d6dfc9acb58902dca1db6da7cf22a6dd284ded08ad6bf1ac7b207fc"}, + {file = "pyscard-2.2.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc2157faa3e75bfb81f393215c2fb980757a5f466015acb6cd221769ba5fc52d"}, + {file = "pyscard-2.2.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:8a682ecb2ac56d88f265f2bc0afe032f8ffc2ec544f384d7a0cdea2d08cae35c"}, + {file = "pyscard-2.2.1-cp312-cp312-win32.whl", hash = "sha256:0a96499b4e910ad4a8244d5406dc6afb4c91812e1124b992832b48e9e4d93b7e"}, + {file = "pyscard-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7acb878270ee58379474646fa6be17dd101b8d870eeadb004f3c2cad736b0b09"}, + {file = "pyscard-2.2.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:803b52f04389456a011ae8b3c02bcdc232e69b32c137b8b5c8695430bb2006af"}, + {file = "pyscard-2.2.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:dc926ba396c1fa6e4db1007b9e62b2f330c79c943c3bbbb893908f589071fc86"}, + {file = "pyscard-2.2.1-cp313-cp313-win32.whl", hash = "sha256:2aca599294cd5178d359627b9b58a8e636ea3ebd73b70da79a95c684be985c83"}, + {file = "pyscard-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:9c33a6cd75479f3f2e1f812399d228e371f030d6f0630b69c34a02519bbf6dca"}, + {file = "pyscard-2.2.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:affafc324ed4a8e735c392e7576f8b55c26a7f2c4f529e3ccb2adf88531d85a4"}, + {file = "pyscard-2.2.1-cp39-cp39-win32.whl", hash = "sha256:b209b6f4c996f9c4a7e04fb3e3e8210f4175986b2bc36ef5d735667d53071381"}, + {file = "pyscard-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:4b7615ff1c6b620136ce554e528affe93bdd9f705601ac23453c2c5d56bf979b"}, + {file = "pyscard-2.2.1.tar.gz", hash = "sha256:920e688a5108224cb19b915c3fd7ea7cf3d1aa379587ffd087973e84c13f8d94"}, ] [package.extras] @@ -670,7 +671,7 @@ optional = false python-versions = "*" groups = ["main"] files = [] -develop = false +develop = true [package.dependencies] bidict = "*" @@ -689,10 +690,8 @@ pyyaml = ">=5.1" termcolor = "*" [package.source] -type = "git" -url = "https://github.com/osmocom/pySim.git" -reference = "HEAD" -resolved_reference = "712946eddb9eedce30b44276d7bd75f40c9a69b9" +type = "directory" +url = "../pysim" [[package]] name = "pytlv" @@ -787,6 +786,21 @@ pygments = ">=2.13.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "rich-argparse" +version = "1.6.0" +description = "Rich help formatters for argparse and optparse" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "rich_argparse-1.6.0-py3-none-any.whl", hash = "sha256:fbe70a1d821b3f2fa8958cddf0cae131870a6e9faa04ab52b409cb1eda809bd7"}, + {file = "rich_argparse-1.6.0.tar.gz", hash = "sha256:092083c30da186f25bcdff8b1d47fdfb571288510fb051e0488a72cc3128de13"}, +] + +[package.dependencies] +rich = ">=11.0.0" + [[package]] name = "six" version = "1.17.0" @@ -845,4 +859,4 @@ files = [ [metadata] lock-version = "2.1" python-versions = ">=3.13" -content-hash = "d787a3424fd3e8689e3e2b99f4e6225e7f78400d0fe0eb11117972c96d9ce99d" +content-hash = "0f33c17a00302b58f79d1748001e128c11b8f27149fd66a329fd2c8c1990cf3d" diff --git a/pyproject.toml b/pyproject.toml index f189a6f..1bcfcd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,9 +9,10 @@ readme = "README.md" requires-python = ">=3.13" dependencies = [ "rich (>=13.9.4,<14.0.0)", - "pysim @ git+https://github.com/osmocom/pySim.git", "pyshark (>=0.6,<0.7)", "argcomplete (>=3.5.3,<4.0.0)", + "rich-argparse (>=1.6.0,<2.0.0)", + "pysim @ file:///home/niklas/Documents/documents/uni/master_thesis/pysim", ] @@ -21,3 +22,6 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.group.dev.dependencies] black = "^24.10.0" + +[tool.poetry.dependencies] +pysim = {develop = true} diff --git a/resimulate/__init__.py b/resimulate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/resimulate/commands/record.py b/resimulate/commands/record.py index 7a6e1c4..d419d45 100644 --- a/resimulate/commands/record.py +++ b/resimulate/commands/record.py @@ -1,24 +1,18 @@ import pickle -from queue import Empty, Queue +import signal +from queue import Empty, Queue, ShutDown from threading import Thread -import time from pySim.apdu import Apdu, ApduCommand from pySim.apdu_source.gsmtap import ApduSource +from rich.align import Align +from rich.console import Group from rich.live import Live +from rich.progress import BarColumn, Progress, TextColumn, TimeElapsedColumn +from rich.text import Text from util.logger import log from util.tracer import Tracer -from rich.console import Group -from rich.panel import Panel -from rich.progress import ( - BarColumn, - Progress, - SpinnerColumn, - TextColumn, - TimeElapsedColumn, -) - class Recorder: def __init__(self, source: ApduSource): @@ -30,6 +24,10 @@ class Recorder: self.tracer_thread = Thread( target=self.tracer.main, args=(self.package_queue,), daemon=True ) + signal.signal(signal.SIGINT, self.__signal_handler) + + def __signal_handler(self, sig, frame): + self.package_queue.shutdown(immediate=True) def record(self, output_path: str, timeout: int): capture_progress = Progress( @@ -47,8 +45,12 @@ class Recorder: ) main_group = Group( - Panel(capture_progress), + # Panel(capture_progress, title="APDU Packets captured", expand=False), overall_progress, + Align.left( + Text.assemble("Press ", ("Ctrl+C", "bold red"), " to stop capturing."), + vertical="bottom", + ), ) overall_task_id = overall_progress.add_task( @@ -57,7 +59,7 @@ class Recorder: total=None, ) - with Live(main_group): + with Live(main_group) as live: self.tracer_thread.start() while self.tracer_thread.is_alive(): @@ -69,23 +71,28 @@ class Recorder: log.debug("No more APDU packets to capture.") break - capture_task_id = capture_progress.add_task( + log.info("Captured %s %s", apdu_command._name, apdu) + + """ capture_task_id = capture_progress.add_task( "", completed=len(self.captured_apdus), packet_type=str(apdu_command._name) or "", packet_description=str(apdu_command.path_str), packet_code=str(apdu_command.col_sw), - ) + ) """ self.captured_apdus.append(apdu) - capture_progress.stop_task(capture_task_id) + """ capture_progress.stop_task(capture_task_id) """ except TimeoutError: log.debug("Timeout reached, stopping capture.") break except Empty: log.debug("No more APDU packets to capture.") break + except ShutDown: + log.debug("Shutting down capture.") + break except UnboundLocalError as e: log.debug("Error capturing APDU packets: %s", e) break @@ -95,8 +102,6 @@ class Recorder: description=f"[bold green]{len(self.captured_apdus)} packet(s) captured!", ) - capture_progress.stop_task(capture_task_id) - overall_progress.update( overall_task_id, description="[bold yellow]Saving captured APDU commands...", @@ -106,7 +111,6 @@ class Recorder: with open(output_path, "wb") as f: pickle.dump(self.captured_apdus, f) - time.sleep(3) overall_progress.update( overall_task_id, diff --git a/resimulate/commands/replay.py b/resimulate/commands/replay.py index 09d0fca..a14bd9e 100644 --- a/resimulate/commands/replay.py +++ b/resimulate/commands/replay.py @@ -1 +1,53 @@ -# https://github.com/Textualize/rich/blob/master/examples/dynamic_progress.py +import pickle + +from osmocom.utils import b2h +from pySim.apdu import Apdu +from pySim.app import init_card +from pySim.card_handler import CardHandler +from rich.align import Align +from rich.console import Group +from rich.live import Live +from rich.progress import BarColumn, Progress, TextColumn, TimeElapsedColumn +from rich.text import Text +from util.logger import log +from util.pcsc_link import PcscLink + + +class Replayer: + def __init__(self, device: int): + self.pcsc_link = PcscLink(device=device) + self.card_handler = CardHandler(self.pcsc_link) + self.runtime_state, self.card = init_card(self.card_handler) + + def replay(self, input_path: str): + progress = Progress( + TimeElapsedColumn(), + BarColumn(), + TextColumn("{task.description}"), + ) + + main_group = Group( + progress, + Align.left( + Text.assemble( + "Press ", ("Ctrl+C", "bold red"), " to stop replaying APDUs." + ), + vertical="bottom", + ), + ) + + progress_id = progress.add_task( + f"[bold red]Loading APDUs from {input_path}...", start=True, total=None + ) + + with Live(main_group): + with open(input_path, "rb") as f: + apdus: list[Apdu] = pickle.load(f) + + with self.pcsc_link as link: + for id, apdu in enumerate(apdus): + progress.update( + progress_id, description=f"Replaying APDU {id} / {len(apdus)}" + ) + data, sw = link.send_tpdu(b2h(apdu)) + log.debug("APDU: %s, SW: %s", b2h(apdu), sw) diff --git a/resimulate/exceptions.py b/resimulate/exceptions.py new file mode 100644 index 0000000..e9c087f --- /dev/null +++ b/resimulate/exceptions.py @@ -0,0 +1,2 @@ +class PcscError(Exception): + pass diff --git a/resimulate/resimulate.py b/resimulate/resimulate.py index a1956c3..dae98ec 100755 --- a/resimulate/resimulate.py +++ b/resimulate/resimulate.py @@ -4,13 +4,14 @@ import argparse import argcomplete -from pySim.apdu_source.gsmtap import GsmtapApduSource - from commands.record import Recorder +from commands.replay import Replayer +from pySim.apdu_source.gsmtap import GsmtapApduSource +from rich_argparse import RichHelpFormatter parser = argparse.ArgumentParser( description="ReSIMulate is a terminal application built for eSIM and SIM-specific APDU analysis. It captures APDU commands, saves them, and replays them to facilitate differential testing, ensuring accurate validation and debugging of SIM interactions.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter, + formatter_class=RichHelpFormatter, ) subparsers = parser.add_subparsers( @@ -65,11 +66,11 @@ replay_parser.add_argument( help="File containing APDU commands to replay (e.g., 'commands.apdu').", ) replay_parser.add_argument( - "-d", - "--device", - type=str, - default="default_device", - help="Target simtrace device to send APDU commands (default: 'default_device').", + "-p", + "--pcsc-device", + type=int, + default=0, + help="Target simtrace device to send APDU commands (default: 0).", ) if __name__ == "__main__": @@ -83,7 +84,8 @@ if __name__ == "__main__": recorder.record(args.output, args.timeout) elif args.command == "replay": - pass + replayer = Replayer(args.pcsc_device) + replayer.replay(args.input.name) else: raise ValueError(f"Unsupported command: {args.command}") diff --git a/resimulate/util/apdu_highlighter.py b/resimulate/util/apdu_highlighter.py new file mode 100644 index 0000000..1885cb0 --- /dev/null +++ b/resimulate/util/apdu_highlighter.py @@ -0,0 +1,26 @@ +from rich.highlighter import RegexHighlighter + + +class ApduHighlighter(RegexHighlighter): + + base_style = "apdu." + highlights = [ + # Class name (e.g., Apdu) + r"(?P\w+)\(", + # CLA (2 hex digits) + r"(?P[0-9A-F]{2})\s", + # INS (2 hex digits) + r"(?P[0-9A-F]{2})\s", + # P1 (2 hex digits) + r"(?P[0-9A-F]{2})\s", + # P2 (2 hex digits) + r"(?P[0-9A-F]{2})\s", + # P3 (2 hex digits) + r"(?P[0-9A-F]{2})\s", + # Command Data (hex bytes separated by spaces) + r"(?P(?:[0-9A-F]{2}\s?)+)", + # Response Data (hex bytes separated by spaces) + r"(?P(?:[0-9A-F]{2}\s?)+)", + # SW (4 hex digits) + r"(?P[0-9A-F]{4})\)", + ] diff --git a/resimulate/util/logger.py b/resimulate/util/logger.py index bb28f25..91576f1 100644 --- a/resimulate/util/logger.py +++ b/resimulate/util/logger.py @@ -1,6 +1,8 @@ import logging -from rich.logging import RichHandler + from rich.console import Console +from rich.logging import RichHandler +from util.apdu_highlighter import ApduHighlighter class RichLogger: @@ -22,8 +24,10 @@ class RichLogger: self.logger = logging.getLogger("rich") def get_logger(self, console: Console = None) -> logging.Logger: - if console: - self._initialize(console) + if not console: + console = Console(highlighter=ApduHighlighter()) + + self._initialize(console) return self.logger diff --git a/resimulate/util/pcsc_link.py b/resimulate/util/pcsc_link.py new file mode 100644 index 0000000..be7e407 --- /dev/null +++ b/resimulate/util/pcsc_link.py @@ -0,0 +1,98 @@ +from exceptions import PcscError +from osmocom.utils import Hexstr, h2i, i2h +from pySim.transport import LinkBaseTpdu +from pySim.utils import ResTuple +from smartcard import System +from smartcard.CardConnection import CardConnection +from smartcard.CardRequest import CardRequest +from smartcard.Exceptions import ( + CardConnectionException, + CardRequestTimeoutException, + NoCardException, +) +from smartcard.ExclusiveConnectCardConnection import ExclusiveConnectCardConnection +from util.logger import log + + +class PcscLink(LinkBaseTpdu): + protocol = CardConnection.T0_protocol + + def __init__(self, device: int, **kwargs): + super().__init__(**kwargs) + + readers = System.readers() + if device > len(readers): + raise PcscError(f"Device with index {device} not found.") + + self.pcsc_device = readers[device] + self.card_connection = ExclusiveConnectCardConnection( + self.pcsc_device.createConnection() + ) + + def __str__(self) -> str: + return "PCSC[%s]" % (self._reader) + + def __del__(self): + try: + self.card_connection.disconnect() + except: + pass + + def __enter__(self): + self.connect() + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.card_connection.disconnect() + log.debug("Disconnected from device %s", self.pcsc_device) + + def connect(self): + try: + self.card_connection.disconnect() + self.card_connection.connect() + supported_protocols = self.card_connection.getSupportedProtocols() + self.card_connection.disconnect() + + if supported_protocols & CardConnection.T0_protocol: + protocol = CardConnection.T0_protocol + elif supported_protocols & CardConnection.T1_protocol: + protocol = CardConnection.T1_protocol + else: + raise PcscError("No supported protocol found.") + + log.debug( + "Connecting to device %s using protocol %s", self.pcsc_device, protocol + ) + + self.card_connection.connect(protocol=protocol) + except (CardConnectionException, NoCardException) as e: + raise PcscError from e + + log.debug("Connected to device %s", self.pcsc_device) + + def disconnect(self): + self.card_connection.disconnect() + log.debug("Disconnected from device %s", self.pcsc_device) + + def _reset_card(self): + self.disconnect() + self.connect() + + def wait_for_card(self, timeout: int | None = None, newcardonly: bool = False): + card_request = CardRequest( + readers=[self.pcsc_device], timeout=timeout, newcardonly=newcardonly + ) + try: + log.debug("Waiting for card on device %s", self.pcsc_device) + card_request.waitforcard() + except CardRequestTimeoutException as e: + raise PcscError from e + + self.__connect() + + def send_tpdu(self, tpdu: Hexstr) -> ResTuple: + try: + data, sw1, sw2 = self.card_connection.transmit(h2i(tpdu)) + return i2h(data) + i2h([sw1, sw2]) + except CardConnectionException as e: + raise PcscError from e diff --git a/resimulate/util/tracer.py b/resimulate/util/tracer.py index 937467e..1f57a08 100644 --- a/resimulate/util/tracer.py +++ b/resimulate/util/tracer.py @@ -1,22 +1,27 @@ from queue import Queue from pySim.apdu import ApduDecoder, CardReset +from pySim.apdu.global_platform import ApduCommands as GlobalPlatformCommands from pySim.apdu.ts_31_102 import ApduCommands as UsimApduCommands from pySim.apdu.ts_102_221 import ApduCommands as UiccApduCommands from pySim.apdu.ts_102_221 import UiccSelect, UiccStatus +from pySim.apdu.ts_102_222 import ApduCommands as ManageApduCommands from pySim.apdu_source import ApduSource +from pySim.ara_m import CardApplicationARAM from pySim.cards import UiccCardBase from pySim.commands import SimCardCommands from pySim.euicc import CardApplicationECASD, CardApplicationISDR +from pySim.global_platform import CardApplicationISD from pySim.runtime import RuntimeState from pySim.ts_31_102 import CardApplicationUSIM from pySim.ts_31_103 import CardApplicationISIM from pySim.ts_102_221 import CardProfileUICC - from util.dummy_sim_link import DummySimLink from util.logger import log -APDU_COMMANDS = UiccApduCommands + UsimApduCommands +APDU_COMMANDS = ( + UiccApduCommands + UsimApduCommands + ManageApduCommands + GlobalPlatformCommands +) # Taken from the pySim project and modified for the ReSIMulate project @@ -29,6 +34,8 @@ class Tracer: profile.add_application(CardApplicationISIM()) profile.add_application(CardApplicationISDR()) profile.add_application(CardApplicationECASD()) + profile.add_application(CardApplicationARAM()) + profile.add_application(CardApplicationISD()) scc = SimCardCommands(transport=DummySimLink()) card = UiccCardBase(scc) @@ -53,7 +60,7 @@ class Tracer: package_queue.task_done() return except Exception as e: - log.error("Error reading APDU: %s", e) + log.error("Error reading APDU (%s): %s", apdu, e) continue if apdu is None: @@ -71,10 +78,10 @@ class Tracer: try: apdu_command.process(self.runtime_state) except ValueError as e: - log.error("Error processing APDU: %s", e) + log.error("Error reading APDU (%s): %s", apdu, e) continue except AttributeError as e: - log.error("Error processing APDU: %s", e) + log.error("Error processing APDU (%s): %s", apdu, e) return # Avoid cluttering the log with too much verbosity