mirror of https://gerrit.osmocom.org/pysim
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:
parent
05ca36b3f3
commit
63f572df42
|
@ -130,12 +130,19 @@ class CardFile(object):
|
||||||
|
|
||||||
class CardDF(CardFile):
|
class CardDF(CardFile):
|
||||||
"""DF (Dedicated File) in the smart card filesystem. Those are basically sub-directories."""
|
"""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):
|
def __init__(self, **kwargs):
|
||||||
if not isinstance(self, CardADF):
|
if not isinstance(self, CardADF):
|
||||||
if not 'fid' in kwargs:
|
if not 'fid' in kwargs:
|
||||||
raise TypeError('fid is mandatory for all DF')
|
raise TypeError('fid is mandatory for all DF')
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.children = dict()
|
self.children = dict()
|
||||||
|
self.shell_commands = [self.ShellCommands()]
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "DF(%s)" % (super().__str__())
|
return "DF(%s)" % (super().__str__())
|
||||||
|
@ -614,17 +621,48 @@ class RuntimeState(object):
|
||||||
else:
|
else:
|
||||||
return self.profile.interpret_sw(sw)
|
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):
|
def select(self, name, cmd_app=None):
|
||||||
"""Change current directory"""
|
"""Change current directory"""
|
||||||
sels = self.selected_file.get_selectables()
|
sels = self.selected_file.get_selectables()
|
||||||
if is_hex(name):
|
if is_hex(name):
|
||||||
name = name.lower()
|
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:
|
if name in sels:
|
||||||
f = sels[name]
|
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:
|
try:
|
||||||
if isinstance(f, CardADF):
|
if isinstance(f, CardADF):
|
||||||
(data, sw) = self.card._scc.select_adf(f.aid)
|
(data, sw) = self.card._scc.select_adf(f.aid)
|
||||||
|
@ -636,14 +674,16 @@ class RuntimeState(object):
|
||||||
if not k:
|
if not k:
|
||||||
raise(swm)
|
raise(swm)
|
||||||
raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1]))
|
raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1]))
|
||||||
# register commands of new file
|
select_resp = f.decode_select_response(data)
|
||||||
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):
|
|
||||||
else:
|
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):
|
def read_binary(self, length=None, offset=0):
|
||||||
if not isinstance(self.selected_file, TransparentEF):
|
if not isinstance(self.selected_file, TransparentEF):
|
||||||
|
|
Loading…
Reference in New Issue