filesystem: allow selection of arbitrary files

Some cards may have additional propritary EF files which pySim-shell
does not support. If the user knows the exact FID the file can still be
selected and it is possible to read the file type and memory model from
the select response. This info can be used to create a new file object
at runtime that will work like any other EF/DF.

Change-Id: Iafff97443130f8bb8c5bc68f51d2fe1d93fff07c
Related: OS#4963
This commit is contained in:
Philipp Maier 2021-03-09 22:42:47 +01:00 committed by Harald Welte
parent 05ca36b3f3
commit 63f572df42
1 changed files with 51 additions and 11 deletions

View File

@ -130,12 +130,19 @@ class CardFile(object):
class CardDF(CardFile):
"""DF (Dedicated File) in the smart card filesystem. Those are basically sub-directories."""
@with_default_category('DF/ADF Commands')
class ShellCommands(CommandSet):
def __init__(self):
super().__init__()
def __init__(self, **kwargs):
if not isinstance(self, CardADF):
if not 'fid' in kwargs:
raise TypeError('fid is mandatory for all DF')
super().__init__(**kwargs)
self.children = dict()
self.shell_commands = [self.ShellCommands()]
def __str__(self):
return "DF(%s)" % (super().__str__())
@ -614,17 +621,48 @@ class RuntimeState(object):
else:
return self.profile.interpret_sw(sw)
def probe_file(self, fid, cmd_app=None):
"""
blindly try to select a file and automatically add a matching file
object if the file actually exists
"""
if not is_hex(fid, 4, 4):
raise ValueError("Cannot select unknown file by name %s, only hexadecimal 4 digit FID is allowed" % fid)
try:
(data, sw) = self.card._scc.select_file(fid)
except SwMatchError as swm:
k = self.interpret_sw(swm.sw_actual)
if not k:
raise(swm)
raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1]))
select_resp = self.selected_file.decode_select_response(data)
if (select_resp['file_descriptor']['file_type'] == 'df'):
f = CardDF(fid=fid, sfid=None, name="DF." + str(fid).upper(), desc="dedicated file, manually added at runtime")
else:
if (select_resp['file_descriptor']['structure'] == 'transparent'):
f = TransparentEF(fid=fid, sfid=None, name="EF." + str(fid).upper(), desc="elementry file, manually added at runtime")
else:
f = LinFixedEF(fid=fid, sfid=None, name="EF." + str(fid).upper(), desc="elementry file, manually added at runtime")
self.selected_file.add_files([f])
self.selected_file = f
return select_resp
def select(self, name, cmd_app=None):
"""Change current directory"""
sels = self.selected_file.get_selectables()
if is_hex(name):
name = name.lower()
# unregister commands of old file
if cmd_app and self.selected_file.shell_commands:
for c in self.selected_file.shell_commands:
cmd_app.unregister_command_set(c)
if name in sels:
f = sels[name]
# unregister commands of old file
if cmd_app and self.selected_file.shell_commands:
for c in self.selected_file.shell_commands:
cmd_app.unregister_command_set(c)
try:
if isinstance(f, CardADF):
(data, sw) = self.card._scc.select_adf(f.aid)
@ -636,14 +674,16 @@ class RuntimeState(object):
if not k:
raise(swm)
raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1]))
# register commands of new file
if cmd_app and self.selected_file.shell_commands:
for c in self.selected_file.shell_commands:
cmd_app.register_command_set(c)
return f.decode_select_response(data)
#elif looks_like_fid(name):
select_resp = f.decode_select_response(data)
else:
raise ValueError("Cannot select unknown %s" % (name))
select_resp = self.probe_file(name, cmd_app)
# register commands of new file
if cmd_app and self.selected_file.shell_commands:
for c in self.selected_file.shell_commands:
cmd_app.register_command_set(c)
return select_resp
def read_binary(self, length=None, offset=0):
if not isinstance(self.selected_file, TransparentEF):