forked from public/pysim
ts_102_221: Implement File Descriptor using construct
This automatically adds encoding support, which is needed for upcoming CREATE FILE support. Change-Id: Ia40dba4aab6ceb9d81fd170f7efa8dad1f9b43d0
This commit is contained in:
@@ -80,9 +80,11 @@ This will
|
|||||||
pySIM-shell (MF)> select ADF.USIM
|
pySIM-shell (MF)> select ADF.USIM
|
||||||
{
|
{
|
||||||
"file_descriptor": {
|
"file_descriptor": {
|
||||||
"shareable": true,
|
"file_descriptor_byte": {
|
||||||
"file_type": "df",
|
"shareable": true,
|
||||||
"structure": "no_info_given"
|
"file_type": "df",
|
||||||
|
"structure": "no_info_given"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"df_name": "A0000000871002FFFFFFFF8907090000",
|
"df_name": "A0000000871002FFFFFFFF8907090000",
|
||||||
"proprietary_info": {
|
"proprietary_info": {
|
||||||
|
|||||||
@@ -528,8 +528,7 @@ class PySimCommands(CommandSet):
|
|||||||
self._cmd.poutput("# file: %s (%s)" % (
|
self._cmd.poutput("# file: %s (%s)" % (
|
||||||
self._cmd.rs.selected_file.name, self._cmd.rs.selected_file.fid))
|
self._cmd.rs.selected_file.name, self._cmd.rs.selected_file.fid))
|
||||||
|
|
||||||
fd = fcp_dec['file_descriptor']
|
structure = self._cmd.rs.selected_file_structure()
|
||||||
structure = fd['structure']
|
|
||||||
self._cmd.poutput("# structure: %s" % str(structure))
|
self._cmd.poutput("# structure: %s" % str(structure))
|
||||||
|
|
||||||
for f in df_path_list:
|
for f in df_path_list:
|
||||||
@@ -545,8 +544,8 @@ class PySimCommands(CommandSet):
|
|||||||
self._cmd.poutput("update_binary " + str(result[0]))
|
self._cmd.poutput("update_binary " + str(result[0]))
|
||||||
elif structure == 'cyclic' or structure == 'linear_fixed':
|
elif structure == 'cyclic' or structure == 'linear_fixed':
|
||||||
# Use number of records specified in select response
|
# Use number of records specified in select response
|
||||||
if 'num_of_rec' in fd:
|
num_of_rec = self._cmd.rs.selected_file_num_of_rec()
|
||||||
num_of_rec = fd['num_of_rec']
|
if num_of_rec:
|
||||||
for r in range(1, num_of_rec + 1):
|
for r in range(1, num_of_rec + 1):
|
||||||
if as_json:
|
if as_json:
|
||||||
result = self._cmd.rs.read_record_dec(r)
|
result = self._cmd.rs.read_record_dec(r)
|
||||||
|
|||||||
@@ -773,7 +773,7 @@ class LinFixedEF(CardEF):
|
|||||||
@cmd2.with_argparser(read_recs_parser)
|
@cmd2.with_argparser(read_recs_parser)
|
||||||
def do_read_records(self, opts):
|
def do_read_records(self, opts):
|
||||||
"""Read all records from a record-oriented EF"""
|
"""Read all records from a record-oriented EF"""
|
||||||
num_of_rec = self._cmd.rs.selected_file_fcp['file_descriptor']['num_of_rec']
|
num_of_rec = self._cmd.rs.selected_file_num_of_rec()
|
||||||
for recnr in range(1, 1 + num_of_rec):
|
for recnr in range(1, 1 + num_of_rec):
|
||||||
(data, sw) = self._cmd.rs.read_record(recnr)
|
(data, sw) = self._cmd.rs.read_record(recnr)
|
||||||
if (len(data) > 0):
|
if (len(data) > 0):
|
||||||
@@ -789,7 +789,7 @@ class LinFixedEF(CardEF):
|
|||||||
@cmd2.with_argparser(read_recs_dec_parser)
|
@cmd2.with_argparser(read_recs_dec_parser)
|
||||||
def do_read_records_decoded(self, opts):
|
def do_read_records_decoded(self, opts):
|
||||||
"""Read + decode all records from a record-oriented EF"""
|
"""Read + decode all records from a record-oriented EF"""
|
||||||
num_of_rec = self._cmd.rs.selected_file_fcp['file_descriptor']['num_of_rec']
|
num_of_rec = self._cmd.rs.selected_file_num_of_rec()
|
||||||
# collect all results in list so they are rendered as JSON list when printing
|
# collect all results in list so they are rendered as JSON list when printing
|
||||||
data_list = []
|
data_list = []
|
||||||
for recnr in range(1, 1 + num_of_rec):
|
for recnr in range(1, 1 + num_of_rec):
|
||||||
@@ -1279,6 +1279,21 @@ class RuntimeState(object):
|
|||||||
pass
|
pass
|
||||||
return apps_taken
|
return apps_taken
|
||||||
|
|
||||||
|
def selected_file_descriptor_byte(self) -> dict:
|
||||||
|
return self.selected_file_fcp['file_descriptor']['file_descriptor_byte']
|
||||||
|
|
||||||
|
def selected_file_shareable(self) -> bool:
|
||||||
|
return self.selected_file_descriptor_byte()['shareable']
|
||||||
|
|
||||||
|
def selected_file_structure(self) -> str:
|
||||||
|
return self.selected_file_descriptor_byte()['structure']
|
||||||
|
|
||||||
|
def selected_file_type(self) -> str:
|
||||||
|
return self.selected_file_descriptor_byte()['file_type']
|
||||||
|
|
||||||
|
def selected_file_num_of_rec(self) -> Optional[int]:
|
||||||
|
return self.selected_file_fcp['file_descriptor'].get('num_of_rec')
|
||||||
|
|
||||||
def reset(self, cmd_app=None) -> Hexstr:
|
def reset(self, cmd_app=None) -> Hexstr:
|
||||||
"""Perform physical card reset and obtain ATR.
|
"""Perform physical card reset and obtain ATR.
|
||||||
Args:
|
Args:
|
||||||
@@ -1350,11 +1365,11 @@ class RuntimeState(object):
|
|||||||
raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1]))
|
raise RuntimeError("%s: %s - %s" % (swm.sw_actual, k[0], k[1]))
|
||||||
|
|
||||||
select_resp = self.selected_file.decode_select_response(data)
|
select_resp = self.selected_file.decode_select_response(data)
|
||||||
if (select_resp['file_descriptor']['file_type'] == 'df'):
|
if (select_resp['file_descriptor']['file_descriptor_byte']['file_type'] == 'df'):
|
||||||
f = CardDF(fid=fid, sfid=None, name="DF." + str(fid).upper(),
|
f = CardDF(fid=fid, sfid=None, name="DF." + str(fid).upper(),
|
||||||
desc="dedicated file, manually added at runtime")
|
desc="dedicated file, manually added at runtime")
|
||||||
else:
|
else:
|
||||||
if (select_resp['file_descriptor']['structure'] == 'transparent'):
|
if (select_resp['file_descriptor']['file_descriptor_byte']['structure'] == 'transparent'):
|
||||||
f = TransparentEF(fid=fid, sfid=None, name="EF." + str(fid).upper(),
|
f = TransparentEF(fid=fid, sfid=None, name="EF." + str(fid).upper(),
|
||||||
desc="elementary file, manually added at runtime")
|
desc="elementary file, manually added at runtime")
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from construct import *
|
from construct import *
|
||||||
|
from construct import Optional as COptional
|
||||||
from pySim.construct import *
|
from pySim.construct import *
|
||||||
from pySim.utils import *
|
from pySim.utils import *
|
||||||
from pySim.filesystem import *
|
from pySim.filesystem import *
|
||||||
@@ -87,34 +88,22 @@ class TotalFileSize(BER_TLV_IE, tag=0x81):
|
|||||||
|
|
||||||
# ETSI TS 102 221 11.1.1.4.3
|
# ETSI TS 102 221 11.1.1.4.3
|
||||||
class FileDescriptor(BER_TLV_IE, tag=0x82):
|
class FileDescriptor(BER_TLV_IE, tag=0x82):
|
||||||
def _from_bytes(self, in_bin: bytes):
|
class BerTlvAdapter(Adapter):
|
||||||
out = {}
|
def _parse(self, obj, context, path):
|
||||||
ft_dict = {
|
if obj == 0x39:
|
||||||
0: 'working_ef',
|
return 'ber_tlv'
|
||||||
1: 'internal_ef',
|
raise ValidationError
|
||||||
7: 'df'
|
def _build(self, obj, context, path):
|
||||||
}
|
if obj == 'ber_tlv':
|
||||||
fs_dict = {
|
return 0x39
|
||||||
0: 'no_info_given',
|
raise ValidationError
|
||||||
1: 'transparent',
|
|
||||||
2: 'linear_fixed',
|
FDB = Select(BitStruct(Const(0, Bit), 'shareable'/Flag, 'structure'/BerTlvAdapter(Const(0x39, BitsInteger(6)))),
|
||||||
6: 'cyclic',
|
BitStruct(Const(0, Bit), 'shareable'/Flag, 'file_type'/Enum(BitsInteger(3), working_ef=0, internal_ef=1, df=7),
|
||||||
0x39: 'ber_tlv',
|
'structure'/Enum(BitsInteger(3), no_info_given=0, transparent=1, linear_fixed=2, cyclic=6))
|
||||||
}
|
)
|
||||||
fdb = in_bin[0]
|
_construct = Struct('file_descriptor_byte'/FDB, Const(b'\x21'),
|
||||||
ftype = (fdb >> 3) & 7
|
'record_len'/COptional(Int16ub), 'num_of_rec'/COptional(Int16ub))
|
||||||
if fdb & 0xbf == 0x39:
|
|
||||||
fstruct = 0x39
|
|
||||||
else:
|
|
||||||
fstruct = fdb & 7
|
|
||||||
out['shareable'] = True if fdb & 0x40 else False
|
|
||||||
out['file_type'] = ft_dict[ftype] if ftype in ft_dict else ftype
|
|
||||||
out['structure'] = fs_dict[fstruct] if fstruct in fs_dict else fstruct
|
|
||||||
if len(in_bin) >= 5:
|
|
||||||
out['record_len'] = int.from_bytes(in_bin[2:4], 'big')
|
|
||||||
out['num_of_rec'] = int.from_bytes(in_bin[4:5], 'big')
|
|
||||||
self.decoded = out
|
|
||||||
return self.decoded
|
|
||||||
|
|
||||||
# ETSI TS 102 221 11.1.1.4.4
|
# ETSI TS 102 221 11.1.1.4.4
|
||||||
class FileIdentifier(BER_TLV_IE, tag=0x83):
|
class FileIdentifier(BER_TLV_IE, tag=0x83):
|
||||||
@@ -668,7 +657,7 @@ class EF_ARR(LinFixedEF):
|
|||||||
@cmd2.with_argparser(LinFixedEF.ShellCommands.read_recs_dec_parser)
|
@cmd2.with_argparser(LinFixedEF.ShellCommands.read_recs_dec_parser)
|
||||||
def do_read_arr_records(self, opts):
|
def do_read_arr_records(self, opts):
|
||||||
"""Read + decode all EF.ARR records in flattened, human-friendly form."""
|
"""Read + decode all EF.ARR records in flattened, human-friendly form."""
|
||||||
num_of_rec = self._cmd.rs.selected_file_fcp['file_descriptor']['num_of_rec']
|
num_of_rec = self._cmd.rs.selected_file_num_of_rec()
|
||||||
# collect all results in list so they are rendered as JSON list when printing
|
# collect all results in list so they are rendered as JSON list when printing
|
||||||
data_list = []
|
data_list = []
|
||||||
for recnr in range(1, 1 + num_of_rec):
|
for recnr in range(1, 1 + num_of_rec):
|
||||||
|
|||||||
@@ -1109,7 +1109,9 @@ class CardProfileSIM(CardProfile):
|
|||||||
4: 'working_ef'
|
4: 'working_ef'
|
||||||
}
|
}
|
||||||
ret = {
|
ret = {
|
||||||
'file_descriptor': {},
|
'file_descriptor': {
|
||||||
|
'file_descriptor_byte': {},
|
||||||
|
},
|
||||||
'proprietary_info': {},
|
'proprietary_info': {},
|
||||||
}
|
}
|
||||||
ret['file_id'] = b2h(resp_bin[4:6])
|
ret['file_id'] = b2h(resp_bin[4:6])
|
||||||
@@ -1117,7 +1119,7 @@ class CardProfileSIM(CardProfile):
|
|||||||
resp_bin[2:4], 'big')
|
resp_bin[2:4], 'big')
|
||||||
file_type = type_of_file_map[resp_bin[6]
|
file_type = type_of_file_map[resp_bin[6]
|
||||||
] if resp_bin[6] in type_of_file_map else resp_bin[6]
|
] if resp_bin[6] in type_of_file_map else resp_bin[6]
|
||||||
ret['file_descriptor']['file_type'] = file_type
|
ret['file_descriptor']['file_descriptor_byte']['file_type'] = file_type
|
||||||
if file_type in ['mf', 'df']:
|
if file_type in ['mf', 'df']:
|
||||||
ret['file_characteristics'] = b2h(resp_bin[13:14])
|
ret['file_characteristics'] = b2h(resp_bin[13:14])
|
||||||
ret['num_direct_child_df'] = resp_bin[14]
|
ret['num_direct_child_df'] = resp_bin[14]
|
||||||
@@ -1127,7 +1129,7 @@ class CardProfileSIM(CardProfile):
|
|||||||
elif file_type in ['working_ef']:
|
elif file_type in ['working_ef']:
|
||||||
file_struct = struct_of_file_map[resp_bin[13]
|
file_struct = struct_of_file_map[resp_bin[13]
|
||||||
] if resp_bin[13] in struct_of_file_map else resp_bin[13]
|
] if resp_bin[13] in struct_of_file_map else resp_bin[13]
|
||||||
ret['file_descriptor']['structure'] = file_struct
|
ret['file_descriptor']['file_descriptor_byte']['structure'] = file_struct
|
||||||
ret['access_conditions'] = b2h(resp_bin[8:10])
|
ret['access_conditions'] = b2h(resp_bin[8:10])
|
||||||
if resp_bin[11] & 0x01 == 0:
|
if resp_bin[11] & 0x01 == 0:
|
||||||
ret['life_cycle_status_int'] = 'operational_activated'
|
ret['life_cycle_status_int'] = 'operational_activated'
|
||||||
|
|||||||
Reference in New Issue
Block a user