filesystem: pass total_len to construct of when encoding file contents
In our construct models we frequently use a context parameter "total_len", we also pass this parameter to construct when we decode files, but we do not pass it when we generate files. This is a problem, because when total_len is used in the construct model, this parameter must be known also when decoding the file. Let's make sure that the total_len is properly determined and and passed to construct (via pyosmocom). Related: OS#5714 Change-Id: I1b7a51594fbc5d9fe01132c39354a2fa88d53f9b
This commit is contained in:
@@ -743,7 +743,26 @@ class TransparentEF(CardEF):
|
|||||||
return t.to_dict()
|
return t.to_dict()
|
||||||
return {'raw': raw_bin_data.hex()}
|
return {'raw': raw_bin_data.hex()}
|
||||||
|
|
||||||
def encode_bin(self, abstract_data: dict) -> bytearray:
|
def __get_size(self, total_len: Optional[int] = None) -> Optional[int]:
|
||||||
|
"""Get the size (total length) of the file"""
|
||||||
|
|
||||||
|
# Caller has provided the actual total length of the file, this should be the default case
|
||||||
|
if total_len is not None:
|
||||||
|
return total_len
|
||||||
|
|
||||||
|
if self.size is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Alternatively use the recommended size from the specification
|
||||||
|
if self.size[1] is not None:
|
||||||
|
return self.size[1]
|
||||||
|
# In case no recommended size is specified, use the minimum size
|
||||||
|
if self.size[0] is not None:
|
||||||
|
return self.size[0]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def encode_bin(self, abstract_data: dict, total_len: Optional[int] = None) -> bytearray:
|
||||||
"""Encode abstract representation into raw (binary) data.
|
"""Encode abstract representation into raw (binary) data.
|
||||||
|
|
||||||
A derived class would typically provide an _encode_bin() or _encode_hex() method
|
A derived class would typically provide an _encode_bin() or _encode_hex() method
|
||||||
@@ -752,17 +771,18 @@ class TransparentEF(CardEF):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
abstract_data : dict representing the decoded data
|
abstract_data : dict representing the decoded data
|
||||||
|
total_len : expected total length of the encoded data (file size)
|
||||||
Returns:
|
Returns:
|
||||||
binary encoded data
|
binary encoded data
|
||||||
"""
|
"""
|
||||||
method = getattr(self, '_encode_bin', None)
|
method = getattr(self, '_encode_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(abstract_data)
|
return method(abstract_data, total_len = self.__get_size(total_len))
|
||||||
method = getattr(self, '_encode_hex', None)
|
method = getattr(self, '_encode_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return h2b(method(abstract_data))
|
return h2b(method(abstract_data, total_len = self.__get_size(total_len)))
|
||||||
if self._construct:
|
if self._construct:
|
||||||
return build_construct(self._construct, abstract_data)
|
return build_construct(self._construct, abstract_data, {'total_len' : self.__get_size(total_len)})
|
||||||
if self._tlv:
|
if self._tlv:
|
||||||
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
||||||
t.from_dict(abstract_data)
|
t.from_dict(abstract_data)
|
||||||
@@ -770,7 +790,7 @@ class TransparentEF(CardEF):
|
|||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"%s encoder not yet implemented. Patches welcome." % self)
|
"%s encoder not yet implemented. Patches welcome." % self)
|
||||||
|
|
||||||
def encode_hex(self, abstract_data: dict) -> str:
|
def encode_hex(self, abstract_data: dict, total_len: Optional[int] = None) -> str:
|
||||||
"""Encode abstract representation into raw (hex string) data.
|
"""Encode abstract representation into raw (hex string) data.
|
||||||
|
|
||||||
A derived class would typically provide an _encode_bin() or _encode_hex() method
|
A derived class would typically provide an _encode_bin() or _encode_hex() method
|
||||||
@@ -779,18 +799,19 @@ class TransparentEF(CardEF):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
abstract_data : dict representing the decoded data
|
abstract_data : dict representing the decoded data
|
||||||
|
total_len : expected total length of the encoded data (file size)
|
||||||
Returns:
|
Returns:
|
||||||
hex string encoded data
|
hex string encoded data
|
||||||
"""
|
"""
|
||||||
method = getattr(self, '_encode_hex', None)
|
method = getattr(self, '_encode_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(abstract_data)
|
return method(abstract_data, total_len = self.__get_size(total_len))
|
||||||
method = getattr(self, '_encode_bin', None)
|
method = getattr(self, '_encode_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
raw_bin_data = method(abstract_data)
|
raw_bin_data = method(abstract_data, total_len = self.__get_size(total_len))
|
||||||
return b2h(raw_bin_data)
|
return b2h(raw_bin_data)
|
||||||
if self._construct:
|
if self._construct:
|
||||||
return b2h(build_construct(self._construct, abstract_data))
|
return b2h(build_construct(self._construct, abstract_data, {'total_len':self.__get_size(total_len)}))
|
||||||
if self._tlv:
|
if self._tlv:
|
||||||
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
||||||
t.from_dict(abstract_data)
|
t.from_dict(abstract_data)
|
||||||
@@ -1030,7 +1051,26 @@ class LinFixedEF(CardEF):
|
|||||||
return t.to_dict()
|
return t.to_dict()
|
||||||
return {'raw': raw_hex_data}
|
return {'raw': raw_hex_data}
|
||||||
|
|
||||||
def encode_record_hex(self, abstract_data: dict, record_nr: int) -> str:
|
def __get_rec_len(self, total_len: Optional[int] = None) -> Optional[int]:
|
||||||
|
"""Get the length (total length) of the file record"""
|
||||||
|
|
||||||
|
# Caller has provided the actual total length of the record, this should be the default case
|
||||||
|
if total_len is not None:
|
||||||
|
return total_len
|
||||||
|
|
||||||
|
if self.rec_len is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Alternatively use the recommended length from the specification
|
||||||
|
if self.rec_len[1] is not None:
|
||||||
|
return self.rec_len[1]
|
||||||
|
# In case no recommended length is specified, use the minimum length
|
||||||
|
if self.rec_len[0] is not None:
|
||||||
|
return self.rec_len[0]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def encode_record_hex(self, abstract_data: dict, record_nr: int, total_len: Optional[int] = None) -> str:
|
||||||
"""Encode abstract representation into raw (hex string) data.
|
"""Encode abstract representation into raw (hex string) data.
|
||||||
|
|
||||||
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
||||||
@@ -1040,18 +1080,19 @@ class LinFixedEF(CardEF):
|
|||||||
Args:
|
Args:
|
||||||
abstract_data : dict representing the decoded data
|
abstract_data : dict representing the decoded data
|
||||||
record_nr : record number (1 for first record, ...)
|
record_nr : record number (1 for first record, ...)
|
||||||
|
total_len : expected total length of the encoded data (record length)
|
||||||
Returns:
|
Returns:
|
||||||
hex string encoded data
|
hex string encoded data
|
||||||
"""
|
"""
|
||||||
method = getattr(self, '_encode_record_hex', None)
|
method = getattr(self, '_encode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(abstract_data, record_nr=record_nr)
|
return method(abstract_data, record_nr=record_nr, total_len = self.__get_rec_len(total_len))
|
||||||
method = getattr(self, '_encode_record_bin', None)
|
method = getattr(self, '_encode_record_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
raw_bin_data = method(abstract_data, record_nr=record_nr)
|
raw_bin_data = method(abstract_data, record_nr=record_nr, total_len = self.__get_rec_len(total_len))
|
||||||
return b2h(raw_bin_data)
|
return b2h(raw_bin_data)
|
||||||
if self._construct:
|
if self._construct:
|
||||||
return b2h(build_construct(self._construct, abstract_data))
|
return b2h(build_construct(self._construct, abstract_data, {'total_len':self.__get_rec_len(total_len)}))
|
||||||
if self._tlv:
|
if self._tlv:
|
||||||
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
||||||
t.from_dict(abstract_data)
|
t.from_dict(abstract_data)
|
||||||
@@ -1059,7 +1100,7 @@ class LinFixedEF(CardEF):
|
|||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"%s encoder not yet implemented. Patches welcome." % self)
|
"%s encoder not yet implemented. Patches welcome." % self)
|
||||||
|
|
||||||
def encode_record_bin(self, abstract_data: dict, record_nr : int) -> bytearray:
|
def encode_record_bin(self, abstract_data: dict, record_nr : int, total_len: Optional[int] = None) -> bytearray:
|
||||||
"""Encode abstract representation into raw (binary) data.
|
"""Encode abstract representation into raw (binary) data.
|
||||||
|
|
||||||
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
||||||
@@ -1069,17 +1110,18 @@ class LinFixedEF(CardEF):
|
|||||||
Args:
|
Args:
|
||||||
abstract_data : dict representing the decoded data
|
abstract_data : dict representing the decoded data
|
||||||
record_nr : record number (1 for first record, ...)
|
record_nr : record number (1 for first record, ...)
|
||||||
|
total_len : expected total length of the encoded data (record length)
|
||||||
Returns:
|
Returns:
|
||||||
binary encoded data
|
binary encoded data
|
||||||
"""
|
"""
|
||||||
method = getattr(self, '_encode_record_bin', None)
|
method = getattr(self, '_encode_record_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(abstract_data, record_nr=record_nr)
|
return method(abstract_data, record_nr=record_nr, total_len = self.__get_rec_len(total_len))
|
||||||
method = getattr(self, '_encode_record_hex', None)
|
method = getattr(self, '_encode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return h2b(method(abstract_data, record_nr=record_nr))
|
return h2b(method(abstract_data, record_nr=record_nr, total_len = self.__get_rec_len(total_len)))
|
||||||
if self._construct:
|
if self._construct:
|
||||||
return build_construct(self._construct, abstract_data)
|
return build_construct(self._construct, abstract_data, {'total_len':self.__get_rec_len(total_len)})
|
||||||
if self._tlv:
|
if self._tlv:
|
||||||
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
||||||
t.from_dict(abstract_data)
|
t.from_dict(abstract_data)
|
||||||
@@ -1224,7 +1266,20 @@ class TransRecEF(TransparentEF):
|
|||||||
return t.to_dict()
|
return t.to_dict()
|
||||||
return {'raw': raw_hex_data}
|
return {'raw': raw_hex_data}
|
||||||
|
|
||||||
def encode_record_hex(self, abstract_data: dict) -> str:
|
def __get_rec_len(self, total_len: Optional[int] = None) -> Optional[int]:
|
||||||
|
"""Get the length (total length) of the file record"""
|
||||||
|
|
||||||
|
# Caller has provided the actual total length of the record, this should be the default case
|
||||||
|
if total_len is not None:
|
||||||
|
return total_len
|
||||||
|
|
||||||
|
# Alternatively use the record length from the specification
|
||||||
|
if self.rec_len:
|
||||||
|
return self.rec_len
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def encode_record_hex(self, abstract_data: dict, total_len: Optional[int] = None) -> str:
|
||||||
"""Encode abstract representation into raw (hex string) data.
|
"""Encode abstract representation into raw (hex string) data.
|
||||||
|
|
||||||
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
||||||
@@ -1233,17 +1288,19 @@ class TransRecEF(TransparentEF):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
abstract_data : dict representing the decoded data
|
abstract_data : dict representing the decoded data
|
||||||
|
total_len : expected total length of the encoded data (record length)
|
||||||
Returns:
|
Returns:
|
||||||
hex string encoded data
|
hex string encoded data
|
||||||
"""
|
"""
|
||||||
method = getattr(self, '_encode_record_hex', None)
|
method = getattr(self, '_encode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(abstract_data)
|
return method(abstract_data, total_len = self.__get_rec_len(total_len))
|
||||||
method = getattr(self, '_encode_record_bin', None)
|
method = getattr(self, '_encode_record_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return b2h(method(abstract_data))
|
return b2h(method(abstract_data, total_len = self.__get_rec_len(total_len)))
|
||||||
if self._construct:
|
if self._construct:
|
||||||
return b2h(filter_dict(build_construct(self._construct, abstract_data)))
|
return b2h(filter_dict(build_construct(self._construct, abstract_data,
|
||||||
|
{'total_len':self.__get_rec_len(total_len)})))
|
||||||
if self._tlv:
|
if self._tlv:
|
||||||
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
||||||
t.from_dict(abstract_data)
|
t.from_dict(abstract_data)
|
||||||
@@ -1251,7 +1308,7 @@ class TransRecEF(TransparentEF):
|
|||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"%s encoder not yet implemented. Patches welcome." % self)
|
"%s encoder not yet implemented. Patches welcome." % self)
|
||||||
|
|
||||||
def encode_record_bin(self, abstract_data: dict) -> bytearray:
|
def encode_record_bin(self, abstract_data: dict, total_len: Optional[int] = None) -> bytearray:
|
||||||
"""Encode abstract representation into raw (binary) data.
|
"""Encode abstract representation into raw (binary) data.
|
||||||
|
|
||||||
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
A derived class would typically provide an _encode_record_bin() or _encode_record_hex()
|
||||||
@@ -1260,17 +1317,19 @@ class TransRecEF(TransparentEF):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
abstract_data : dict representing the decoded data
|
abstract_data : dict representing the decoded data
|
||||||
|
total_len : expected total length of the encoded data (record length)
|
||||||
Returns:
|
Returns:
|
||||||
binary encoded data
|
binary encoded data
|
||||||
"""
|
"""
|
||||||
method = getattr(self, '_encode_record_bin', None)
|
method = getattr(self, '_encode_record_bin', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return method(abstract_data)
|
return method(abstract_data, total_len = self.__get_rec_len(total_len))
|
||||||
method = getattr(self, '_encode_record_hex', None)
|
method = getattr(self, '_encode_record_hex', None)
|
||||||
if callable(method):
|
if callable(method):
|
||||||
return h2b(method(abstract_data))
|
return h2b(method(abstract_data, total_len = self.__get_rec_len(total_len)))
|
||||||
if self._construct:
|
if self._construct:
|
||||||
return filter_dict(build_construct(self._construct, abstract_data))
|
return filter_dict(build_construct(self._construct, abstract_data,
|
||||||
|
{'total_len':self.__get_rec_len(total_len)}))
|
||||||
if self._tlv:
|
if self._tlv:
|
||||||
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
t = self._tlv() if inspect.isclass(self._tlv) else self._tlv
|
||||||
t.from_dict(abstract_data)
|
t.from_dict(abstract_data)
|
||||||
@@ -1283,8 +1342,8 @@ class TransRecEF(TransparentEF):
|
|||||||
for i in range(0, len(raw_bin_data), self.rec_len)]
|
for i in range(0, len(raw_bin_data), self.rec_len)]
|
||||||
return [self.decode_record_bin(x) for x in chunks]
|
return [self.decode_record_bin(x) for x in chunks]
|
||||||
|
|
||||||
def _encode_bin(self, abstract_data) -> bytes:
|
def _encode_bin(self, abstract_data, **kwargs) -> bytes:
|
||||||
chunks = [self.encode_record_bin(x) for x in abstract_data]
|
chunks = [self.encode_record_bin(x, total_len = kwargs.get('total_len', None)) for x in abstract_data]
|
||||||
# FIXME: pad to file size
|
# FIXME: pad to file size
|
||||||
return b''.join(chunks)
|
return b''.join(chunks)
|
||||||
|
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ class EF_Predefined(LinFixedEF):
|
|||||||
else:
|
else:
|
||||||
return parse_construct(self.construct_others, raw_bin_data)
|
return parse_construct(self.construct_others, raw_bin_data)
|
||||||
|
|
||||||
def _encode_record_bin(self, abstract_data : dict, record_nr : int) -> bytearray:
|
def _encode_record_bin(self, abstract_data : dict, record_nr : int, **kwargs) -> bytearray:
|
||||||
r = None
|
r = None
|
||||||
if record_nr == 1:
|
if record_nr == 1:
|
||||||
r = self.construct_first.build(abstract_data)
|
r = self.construct_first.build(abstract_data)
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ class RuntimeLchan:
|
|||||||
Args:
|
Args:
|
||||||
data : abstract data which is to be encoded and written
|
data : abstract data which is to be encoded and written
|
||||||
"""
|
"""
|
||||||
data_hex = self.selected_file.encode_hex(data)
|
data_hex = self.selected_file.encode_hex(data, self.selected_file_size())
|
||||||
return self.update_binary(data_hex)
|
return self.update_binary(data_hex)
|
||||||
|
|
||||||
def read_record(self, rec_nr: int = 0):
|
def read_record(self, rec_nr: int = 0):
|
||||||
@@ -574,7 +574,7 @@ class RuntimeLchan:
|
|||||||
rec_nr : Record number to read
|
rec_nr : Record number to read
|
||||||
data_hex : Abstract data to be written
|
data_hex : Abstract data to be written
|
||||||
"""
|
"""
|
||||||
data_hex = self.selected_file.encode_record_hex(data, rec_nr)
|
data_hex = self.selected_file.encode_record_hex(data, rec_nr, self.selected_file_record_len())
|
||||||
return self.update_record(rec_nr, data_hex)
|
return self.update_record(rec_nr, data_hex)
|
||||||
|
|
||||||
def retrieve_data(self, tag: int = 0):
|
def retrieve_data(self, tag: int = 0):
|
||||||
|
|||||||
@@ -252,7 +252,7 @@ class EF_USIM_AUTH_KEY(TransparentEF):
|
|||||||
else:
|
else:
|
||||||
return parse_construct(self._construct, raw_bin_data)
|
return parse_construct(self._construct, raw_bin_data)
|
||||||
|
|
||||||
def _encode_bin(self, abstract_data: dict) -> bytearray:
|
def _encode_bin(self, abstract_data: dict, **kwargs) -> bytearray:
|
||||||
if abstract_data['cfg']['algorithm'] == 'tuak':
|
if abstract_data['cfg']['algorithm'] == 'tuak':
|
||||||
return build_construct(self._constr_tuak, abstract_data)
|
return build_construct(self._constr_tuak, abstract_data)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ class EF_SUCI_Calc_Info(TransparentEF):
|
|||||||
out.append({k: v})
|
out.append({k: v})
|
||||||
return out
|
return out
|
||||||
|
|
||||||
def _encode_hex(self, in_json):
|
def _encode_hex(self, in_json, **kwargs):
|
||||||
out_bytes = self._encode_prot_scheme_id_list(
|
out_bytes = self._encode_prot_scheme_id_list(
|
||||||
in_json['prot_scheme_id_list'])
|
in_json['prot_scheme_id_list'])
|
||||||
d = self._expand_pubkey_list(in_json['hnet_pubkey_list'])
|
d = self._expand_pubkey_list(in_json['hnet_pubkey_list'])
|
||||||
@@ -396,8 +396,8 @@ class EF_SUCI_Calc_Info(TransparentEF):
|
|||||||
'hnet_pubkey_list': hnet_pubkey_list
|
'hnet_pubkey_list': hnet_pubkey_list
|
||||||
}
|
}
|
||||||
|
|
||||||
def _encode_bin(self, in_json):
|
def _encode_bin(self, in_json, **kwargs):
|
||||||
return h2b(self._encode_hex(in_json))
|
return h2b(self._encode_hex(in_json, **kwargs))
|
||||||
|
|
||||||
|
|
||||||
class EF_LI(TransRecEF):
|
class EF_LI(TransRecEF):
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class EF_UServiceTable(TransparentEF):
|
|||||||
ret[service_nr]['description'] = self.table[service_nr]
|
ret[service_nr]['description'] = self.table[service_nr]
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _encode_bin(self, in_json):
|
def _encode_bin(self, in_json, **kwargs):
|
||||||
# compute the required binary size
|
# compute the required binary size
|
||||||
bin_len = 0
|
bin_len = 0
|
||||||
for srv in in_json.keys():
|
for srv in in_json.keys():
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ class EF_IMSI(TransparentEF):
|
|||||||
def _decode_hex(self, raw_hex):
|
def _decode_hex(self, raw_hex):
|
||||||
return {'imsi': dec_imsi(raw_hex)}
|
return {'imsi': dec_imsi(raw_hex)}
|
||||||
|
|
||||||
def _encode_hex(self, abstract):
|
def _encode_hex(self, abstract, **kwargs):
|
||||||
return enc_imsi(abstract['imsi'])
|
return enc_imsi(abstract['imsi'])
|
||||||
|
|
||||||
@with_default_category('File-Specific Commands')
|
@with_default_category('File-Specific Commands')
|
||||||
@@ -446,7 +446,7 @@ class EF_ServiceTable(TransparentEF):
|
|||||||
}
|
}
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def _encode_bin(self, in_json):
|
def _encode_bin(self, in_json, **kwargs):
|
||||||
# compute the required binary size
|
# compute the required binary size
|
||||||
bin_len = 0
|
bin_len = 0
|
||||||
for srv in in_json.keys():
|
for srv in in_json.keys():
|
||||||
@@ -969,7 +969,7 @@ class EF_ICCID(TransparentEF):
|
|||||||
def _decode_hex(self, raw_hex):
|
def _decode_hex(self, raw_hex):
|
||||||
return {'iccid': dec_iccid(raw_hex)}
|
return {'iccid': dec_iccid(raw_hex)}
|
||||||
|
|
||||||
def _encode_hex(self, abstract):
|
def _encode_hex(self, abstract, **kwargs):
|
||||||
return enc_iccid(abstract['iccid'])
|
return enc_iccid(abstract['iccid'])
|
||||||
|
|
||||||
# TS 102 221 Section 13.3 / TS 31.101 Secction 13 / TS 51.011 Section 10.1.2
|
# TS 102 221 Section 13.3 / TS 31.101 Secction 13 / TS 51.011 Section 10.1.2
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
010 0123456789abcdef0123456789abcdef0123456789abcdef0123456789
|
010 0123456789abcdef0123456789abcdef0123456789abcdef0123456789
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"alpha_id": null,
|
"alpha_id": "",
|
||||||
"len_of_bcd": 7,
|
"len_of_bcd": 7,
|
||||||
"ton_npi": {
|
"ton_npi": {
|
||||||
"ext": true,
|
"ext": true,
|
||||||
@@ -60,7 +60,7 @@
|
|||||||
"ext4_record_id": 255
|
"ext4_record_id": 255
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"alpha_id": null,
|
"alpha_id": "",
|
||||||
"len_of_bcd": 7,
|
"len_of_bcd": 7,
|
||||||
"ton_npi": {
|
"ton_npi": {
|
||||||
"ext": true,
|
"ext": true,
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
"ext4_record_id": 255
|
"ext4_record_id": 255
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"alpha_id": null,
|
"alpha_id": "",
|
||||||
"len_of_bcd": 7,
|
"len_of_bcd": 7,
|
||||||
"ton_npi": {
|
"ton_npi": {
|
||||||
"ext": true,
|
"ext": true,
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
{
|
{
|
||||||
"alpha_id": null,
|
"alpha_id": "",
|
||||||
"len_of_bcd": 7,
|
"len_of_bcd": 7,
|
||||||
"ton_npi": {
|
"ton_npi": {
|
||||||
"ext": true,
|
"ext": true,
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ import pySim.sysmocom_sja2
|
|||||||
import pySim.gsm_r
|
import pySim.gsm_r
|
||||||
import pySim.cdma_ruim
|
import pySim.cdma_ruim
|
||||||
|
|
||||||
|
from construct import Int8ub, Struct, Padding, this
|
||||||
|
from osmocom.tlv import BER_TLV_IE
|
||||||
|
|
||||||
def get_qualified_name(c):
|
def get_qualified_name(c):
|
||||||
"""return the qualified (by module) name of a class."""
|
"""return the qualified (by module) name of a class."""
|
||||||
return "%s.%s" % (c.__module__, c.__name__)
|
return "%s.%s" % (c.__module__, c.__name__)
|
||||||
@@ -288,6 +291,251 @@ class TransparentEF_Test(unittest.TestCase):
|
|||||||
re_dec = inst.decode_hex(encoded)
|
re_dec = inst.decode_hex(encoded)
|
||||||
self.assertEqual(decoded, re_dec)
|
self.assertEqual(decoded, re_dec)
|
||||||
|
|
||||||
|
|
||||||
|
class filesystem_enc_dec_test(unittest.TestCase):
|
||||||
|
""" The following set of tests is to verify the code paths in filesystem.py. There are several methods to encode
|
||||||
|
or decode a file. Depending on which methods (encode_hex, decode_hex, etc.) or structs (_construct, _tlv) are
|
||||||
|
define in the related file object, the encoding/decoding will take a different code path. In this test we will
|
||||||
|
try out all of the different encoding/decoding variants by defining one test file for each variant. Then we will
|
||||||
|
run an encoding/decoding cycle on each of the test files.
|
||||||
|
|
||||||
|
The test files will also include a padding that is dependent on the total_len keyword argument that is passed
|
||||||
|
via the construct context or via **kwargs in case the hand written encoding methods (encode_hex, encode_record_hex,
|
||||||
|
etc.) are used. This will ensure that total_len is passed correctly in all possible variants.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_encode_TransparentEF(self):
|
||||||
|
|
||||||
|
class TransparentEF_construct(TransparentEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(2, 2),
|
||||||
|
desc='dummy TransparentEF file to test encoding/decoding via _construct'):
|
||||||
|
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
|
||||||
|
self._construct = Struct('test'/Int8ub, Padding(this._.total_len-1))
|
||||||
|
|
||||||
|
class TransparentEF_encode_hex(TransparentEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(2, 2),
|
||||||
|
desc='dummy TransparentEF file to test manual encoding/decoding via _encode/decode_hex'):
|
||||||
|
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
|
||||||
|
def _encode_hex(self, in_json, **kwargs):
|
||||||
|
return "%02x" % in_json['test'] + "00" * (kwargs.get('total_len') -1)
|
||||||
|
def _decode_hex(self, raw_hex):
|
||||||
|
return {'test': int(raw_hex[0:2],16)}
|
||||||
|
|
||||||
|
class TransparentEF_encode_bin(TransparentEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(2, 2),
|
||||||
|
desc='dummy TransparentEF file to test manual encoding/decoding via _encode/decode_bin'):
|
||||||
|
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
|
||||||
|
def _encode_bin(self, in_json, **kwargs):
|
||||||
|
return h2b("%02x" % in_json['test'] + "00" * (kwargs.get('total_len') -1))
|
||||||
|
def _decode_bin(self, raw_bin_data: bytearray):
|
||||||
|
return {'test': int(b2h(raw_bin_data[0:1]),16)}
|
||||||
|
|
||||||
|
class TransparentEF_tlv(TransparentEF):
|
||||||
|
class TestTlv(BER_TLV_IE, tag=0x81):
|
||||||
|
_construct = Int8ub
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(1, 1),
|
||||||
|
desc='dummy TransparentEF file to test encoding/decoding via _tlv'):
|
||||||
|
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
|
||||||
|
self._tlv = TransparentEF_tlv.TestTlv
|
||||||
|
|
||||||
|
class TransparentEF_raw(TransparentEF):
|
||||||
|
class TestTlv(BER_TLV_IE, tag=0x81):
|
||||||
|
_construct = Int8ub
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(1, 1),
|
||||||
|
desc='dummy TransparentEF file to test raw encoding/decoding'):
|
||||||
|
super().__init__(fid, sfid=sfid, name=name, desc=desc, size=size)
|
||||||
|
|
||||||
|
def do_encdec_test(file):
|
||||||
|
res = file.encode_hex({'test':0x41})
|
||||||
|
self.assertEqual(res,hexstr("4100"))
|
||||||
|
res = file.encode_bin({'test':0x41})
|
||||||
|
self.assertEqual(b2h(res),hexstr("4100"))
|
||||||
|
res = file.encode_hex({'test':0x41}, total_len=3)
|
||||||
|
self.assertEqual(res,hexstr("410000"))
|
||||||
|
res = file.encode_bin({'test':0x41}, total_len=3)
|
||||||
|
self.assertEqual(b2h(res),hexstr("410000"))
|
||||||
|
res = file.decode_hex("4100")
|
||||||
|
self.assertEqual(res,{'test':0x41})
|
||||||
|
res = file.decode_bin(b'\x41\x01')
|
||||||
|
self.assertEqual(res,{'test':0x41})
|
||||||
|
|
||||||
|
def do_encdec_test_tlv(file):
|
||||||
|
res = file.encode_hex({'test_tlv':0x41})
|
||||||
|
self.assertEqual(res,hexstr("810141"))
|
||||||
|
res = file.encode_bin({'test_tlv':0x41})
|
||||||
|
self.assertEqual(b2h(res),hexstr("810141"))
|
||||||
|
res = file.decode_hex(hexstr("810141"))
|
||||||
|
self.assertEqual(res,{'test_tlv':0x41})
|
||||||
|
res = file.decode_bin(h2b("810141"))
|
||||||
|
self.assertEqual(res,{'test_tlv':0x41})
|
||||||
|
|
||||||
|
def do_encdec_test_raw(file):
|
||||||
|
res = file.decode_hex("41")
|
||||||
|
self.assertEqual(res,{'raw':'41'})
|
||||||
|
res = file.decode_bin(b'\x41')
|
||||||
|
self.assertEqual(res,{'raw':'41'})
|
||||||
|
|
||||||
|
do_encdec_test(TransparentEF_construct())
|
||||||
|
do_encdec_test(TransparentEF_encode_hex())
|
||||||
|
do_encdec_test(TransparentEF_encode_bin())
|
||||||
|
do_encdec_test_tlv(TransparentEF_tlv())
|
||||||
|
do_encdec_test_raw(TransparentEF_raw())
|
||||||
|
|
||||||
|
def test_encode_LinFixedEF(self):
|
||||||
|
|
||||||
|
class LinFixedEF_construct(LinFixedEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY',
|
||||||
|
desc='dummy LinFixedEF file to test encoding/decoding via _construct', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, rec_len=(2, 2), **kwargs)
|
||||||
|
self._construct = Struct('test'/Int8ub, Padding(this._.total_len-1))
|
||||||
|
|
||||||
|
class LinFixedEF_encode_hex(LinFixedEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY',
|
||||||
|
desc='dummy LinFixedEF file to test manual encoding/decoding via _encode/decode_hex', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, rec_len=(2, 2), **kwargs)
|
||||||
|
def _encode_record_hex(self, in_json, **kwargs):
|
||||||
|
return "%02x" % in_json['test'] + "00" * (kwargs.get('total_len') -1)
|
||||||
|
def _decode_record_hex(self, in_hex, **kwargs):
|
||||||
|
return {'test': int(in_hex[0:2],16)}
|
||||||
|
|
||||||
|
class LinFixedEF_encode_bin(LinFixedEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY',
|
||||||
|
desc='dummy LinFixedEF file to test manual encoding/decoding via _encode/decode_bin', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, rec_len=(2, 2), **kwargs)
|
||||||
|
def _encode_record_bin(self, in_json, **kwargs):
|
||||||
|
return h2b("%02x" % in_json['test'] + "00" * (kwargs.get('total_len') -1))
|
||||||
|
def _decode_record_bin(self, in_bin, **kwargs):
|
||||||
|
return {'test': int(b2h(in_bin[0:1]),16)}
|
||||||
|
|
||||||
|
class LinFixedEF_tlv(LinFixedEF):
|
||||||
|
class TestTlv(BER_TLV_IE, tag=0x81):
|
||||||
|
_construct = Int8ub
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY',
|
||||||
|
desc='dummy LinFixedEF file to test encoding/decoding via _tlv', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, rec_len=(1, 1), **kwargs)
|
||||||
|
self._tlv = LinFixedEF_tlv.TestTlv
|
||||||
|
|
||||||
|
class LinFixedEF_raw(LinFixedEF):
|
||||||
|
class TestTlv(BER_TLV_IE, tag=0x81):
|
||||||
|
_construct = Int8ub
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY',
|
||||||
|
desc='dummy LinFixedEF file to test raw encoding/decoding', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, rec_len=(1, 1), **kwargs)
|
||||||
|
|
||||||
|
def do_encdec_test(file):
|
||||||
|
res = file.encode_record_hex({'test':0x41}, 1)
|
||||||
|
self.assertEqual(res,hexstr("4100"))
|
||||||
|
res = file.encode_record_bin({'test':0x41}, 1)
|
||||||
|
self.assertEqual(b2h(res),hexstr("4100"))
|
||||||
|
res = file.encode_record_hex({'test':0x41}, 1, total_len=3)
|
||||||
|
self.assertEqual(res,hexstr("410000"))
|
||||||
|
res = file.encode_record_bin({'test':0x41}, 1, total_len=3)
|
||||||
|
self.assertEqual(b2h(res),hexstr("410000"))
|
||||||
|
res = file.decode_record_hex("4100", 1)
|
||||||
|
self.assertEqual(res,{'test':0x41})
|
||||||
|
res = file.decode_record_bin(b'\x41\x00', 1)
|
||||||
|
self.assertEqual(res,{'test':0x41})
|
||||||
|
|
||||||
|
def do_encdec_test_tlv(file):
|
||||||
|
res = file.encode_record_hex({'test_tlv':0x41}, 1)
|
||||||
|
self.assertEqual(res,hexstr("810141"))
|
||||||
|
res = file.encode_record_bin({'test_tlv':0x41}, 1)
|
||||||
|
self.assertEqual(b2h(res),hexstr("810141"))
|
||||||
|
res = file.decode_record_hex(hexstr("810141"), 1)
|
||||||
|
self.assertEqual(res,{'test_tlv':0x41})
|
||||||
|
res = file.decode_record_bin(h2b("810141"), 1)
|
||||||
|
self.assertEqual(res,{'test_tlv':0x41})
|
||||||
|
|
||||||
|
def do_encdec_test_raw(file):
|
||||||
|
res = file.decode_record_hex("41", 1)
|
||||||
|
self.assertEqual(res,{'raw':'41'})
|
||||||
|
res = file.decode_record_bin(b'\x41', 1)
|
||||||
|
self.assertEqual(res,{'raw':'41'})
|
||||||
|
|
||||||
|
do_encdec_test(LinFixedEF_construct())
|
||||||
|
do_encdec_test(LinFixedEF_encode_hex())
|
||||||
|
do_encdec_test(LinFixedEF_encode_bin())
|
||||||
|
do_encdec_test_tlv(LinFixedEF_tlv())
|
||||||
|
do_encdec_test_raw(LinFixedEF_raw())
|
||||||
|
|
||||||
|
def test_encode_TransRecEF(self):
|
||||||
|
|
||||||
|
class TransRecEF_construct(TransRecEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(2, 2), rec_len=2,
|
||||||
|
desc='dummy TransRecEF file to test encoding/decoding via _construct', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
|
||||||
|
self._construct = Struct('test'/Int8ub, Padding(this._.total_len-1))
|
||||||
|
|
||||||
|
class TransRecEF_encode_hex(TransRecEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(2, 2), rec_len=2,
|
||||||
|
desc='dummy TransRecEF file to test manual encoding/decoding via _encode/decode_hex', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
|
||||||
|
def _encode_record_hex(self, in_json, **kwargs):
|
||||||
|
return "%02x" % in_json['test'] + "00" * (kwargs.get('total_len') -1)
|
||||||
|
def _decode_record_hex(self, in_hex, **kwargs):
|
||||||
|
return {'test': int(in_hex[0:2],16)}
|
||||||
|
|
||||||
|
class TransRecEF_encode_bin(TransRecEF):
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(2, 2), rec_len=2,
|
||||||
|
desc='dummy TransRecEF file to test manual encoding/decoding via _encode/decode_bin', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
|
||||||
|
def _encode_record_bin(self, in_json, **kwargs):
|
||||||
|
return h2b("%02x" % in_json['test'] + "00" * (kwargs.get('total_len') -1))
|
||||||
|
def _decode_record_bin(self, in_bin, **kwargs):
|
||||||
|
return {'test': int(b2h(in_bin[0:1]),16)}
|
||||||
|
|
||||||
|
class TransRecEF_tlv(TransRecEF):
|
||||||
|
class TestTlv(BER_TLV_IE, tag=0x81):
|
||||||
|
_construct = Int8ub
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(1, 1), rec_len=1,
|
||||||
|
desc='dummy TransRecEF file to test encoding/decoding via _tlv', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
|
||||||
|
self._tlv = TransRecEF_tlv.TestTlv
|
||||||
|
|
||||||
|
class TransRecEF_raw(TransRecEF):
|
||||||
|
class TestTlv(BER_TLV_IE, tag=0x81):
|
||||||
|
_construct = Int8ub
|
||||||
|
def __init__(self, fid='0000', sfid=None, name='EF.DUMMY', size=(1, 1), rec_len=1,
|
||||||
|
desc='dummy TransRecEF file to test raw encoding/decoding', **kwargs):
|
||||||
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, size=size, rec_len=rec_len, **kwargs)
|
||||||
|
|
||||||
|
def do_encdec_test(file):
|
||||||
|
res = file.encode_record_hex({'test':0x41})
|
||||||
|
self.assertEqual(res,hexstr("4100"))
|
||||||
|
res = file.encode_record_bin({'test':0x41})
|
||||||
|
self.assertEqual(b2h(res),hexstr("4100"))
|
||||||
|
res = file.encode_record_hex({'test':0x41}, total_len=3)
|
||||||
|
self.assertEqual(res,hexstr("410000"))
|
||||||
|
res = file.encode_record_bin({'test':0x41}, total_len=3)
|
||||||
|
self.assertEqual(b2h(res),hexstr("410000"))
|
||||||
|
res = file.decode_record_hex("4100")
|
||||||
|
self.assertEqual(res,{'test':0x41})
|
||||||
|
res = file.decode_record_bin(b'\x41\x00')
|
||||||
|
self.assertEqual(res,{'test':0x41})
|
||||||
|
|
||||||
|
def do_encdec_test_tlv(file):
|
||||||
|
res = file.encode_record_hex({'test_tlv':0x41})
|
||||||
|
self.assertEqual(res,hexstr("810141"))
|
||||||
|
res = file.encode_record_bin({'test_tlv':0x41})
|
||||||
|
self.assertEqual(b2h(res),hexstr("810141"))
|
||||||
|
res = file.decode_record_hex(hexstr("810141"))
|
||||||
|
self.assertEqual(res,{'test_tlv':0x41})
|
||||||
|
res = file.decode_record_bin(h2b("810141"))
|
||||||
|
self.assertEqual(res,{'test_tlv':0x41})
|
||||||
|
|
||||||
|
def do_encdec_test_raw(file):
|
||||||
|
res = file.decode_record_hex("41")
|
||||||
|
self.assertEqual(res,{'raw':'41'})
|
||||||
|
res = file.decode_record_bin(b'\x41')
|
||||||
|
self.assertEqual(res,{'raw':'41'})
|
||||||
|
|
||||||
|
do_encdec_test(TransRecEF_construct())
|
||||||
|
do_encdec_test(TransRecEF_encode_hex())
|
||||||
|
do_encdec_test(TransRecEF_encode_bin())
|
||||||
|
do_encdec_test_tlv(TransRecEF_tlv())
|
||||||
|
do_encdec_test_raw(TransRecEF_raw())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
logger.setLevel(logging.DEBUG)
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|||||||
Reference in New Issue
Block a user