filesystem: fix decode_select_response
There are some problems with the usage of decode_select_response. At the moment the ADF files overload the related method to provide decoding of the select responses as per 3gpp TS 102 221. However, this also means that the decoder is only available under ADF.USIM and ADF.ISIM. DF.GSM and DF.TELECOM also overload the decoder method, just like an ADF would do. This decoding method is then implemented as per 3gpp TS 51 011. Since this a a problem on UICCs, the method detects the magic byte 0x62 that can be found at the beginning on every select response of an UICC to defer to the TS 102 221 decoding method. TS 51 011 defines the first two bytes of the select response as RFU. This at least problematic. To solve this there should be a default method for decode_select_response in the profile, which can be used if no file overloads it with a specific decoder. ADFs use specific decoders, but everything else should use the default decoder. When we deal with an UICC, we expect the select response to be consistantly conform to TS 102 221, if we deal with a clasic sim we expect responses as per TS 51 011 only. Since it is still possible to replace the select response decoder we still have the opportunity to have custom select response in cartain DFs and ADFs should we need them. Change-Id: I95e33ec1755727dc9bbbc6016ce2d99a9e66f214 Related: OS#5274
This commit is contained in:
@@ -52,7 +52,7 @@ class CardFile(object):
|
||||
RESERVED_FIDS = ['3f00']
|
||||
|
||||
def __init__(self, fid:str=None, sfid:str=None, name:str=None, desc:str=None,
|
||||
parent:Optional['CardDF']=None):
|
||||
parent:Optional['CardDF']=None, profile:Optional['CardProfile']=None):
|
||||
"""
|
||||
Args:
|
||||
fid : File Identifier (4 hex digits)
|
||||
@@ -60,6 +60,7 @@ class CardFile(object):
|
||||
name : Brief name of the file, lik EF_ICCID
|
||||
desc : Description of the file
|
||||
parent : Parent CardFile object within filesystem hierarchy
|
||||
profile : Card profile that this file should be part of
|
||||
"""
|
||||
if not isinstance(self, CardADF) and fid == None:
|
||||
raise ValueError("fid is mandatory")
|
||||
@@ -72,6 +73,7 @@ class CardFile(object):
|
||||
self.parent = parent
|
||||
if self.parent and self.parent != self and self.fid:
|
||||
self.parent.add_file(self)
|
||||
self.profile = profile
|
||||
self.shell_commands = [] # type: List[CommandSet]
|
||||
|
||||
# Note: the basic properties (fid, name, ect.) are verified when
|
||||
@@ -173,10 +175,34 @@ class CardFile(object):
|
||||
return list(sels.keys())
|
||||
|
||||
def decode_select_response(self, data_hex:str):
|
||||
"""Decode the response to a SELECT command."""
|
||||
"""Decode the response to a SELECT command.
|
||||
|
||||
Args:
|
||||
data_hex: Hex string of the select response
|
||||
"""
|
||||
|
||||
# When the current file does not implement a custom select response decoder,
|
||||
# we just ask the parent file to decode the select response. If this method
|
||||
# is not overloaded by the current file we will again ask the parent file.
|
||||
# This way we recursively travel up the file system tree until we hit a file
|
||||
# that does implement a concrete decoder.
|
||||
if self.parent:
|
||||
return self.parent.decode_select_response(data_hex)
|
||||
|
||||
def get_profile(self):
|
||||
"""Get the profile associated with this file. If this file does not have any
|
||||
profile assigned, try to find a file above (usually the MF) in the filesystem
|
||||
hirarchy that has a profile assigned
|
||||
"""
|
||||
|
||||
# If we have a profile set, return it
|
||||
if self.profile:
|
||||
return self.profile
|
||||
|
||||
# Walk up recursively until we hit a parent that has a profile set
|
||||
if self.parent:
|
||||
return self.parent.get_profile()
|
||||
return None
|
||||
|
||||
class CardDF(CardFile):
|
||||
"""DF (Dedicated File) in the smart card filesystem. Those are basically sub-directories."""
|
||||
@@ -331,12 +357,18 @@ class CardMF(CardDF):
|
||||
def decode_select_response(self, data_hex:str) -> Any:
|
||||
"""Decode the response to a SELECT command.
|
||||
|
||||
This is the fall-back method which doesn't perform any decoding. It mostly
|
||||
exists so specific derived classes can overload it for actual decoding.
|
||||
This is the fall-back method which automatically defers to the standard decoding
|
||||
method defined by the card profile. When no profile is set, then no decoding is
|
||||
performed. Specific derived classes (usually ADF) can overload this method to
|
||||
install specific decoding.
|
||||
"""
|
||||
return data_hex
|
||||
|
||||
profile = self.get_profile()
|
||||
|
||||
if profile:
|
||||
return profile.decode_select_response(data_hex)
|
||||
else:
|
||||
return data_hex
|
||||
|
||||
class CardADF(CardDF):
|
||||
"""ADF (Application Dedicated File) in the smart card filesystem"""
|
||||
@@ -1029,7 +1061,7 @@ class RuntimeState(object):
|
||||
card : pysim.cards.Card instance
|
||||
profile : CardProfile instance
|
||||
"""
|
||||
self.mf = CardMF()
|
||||
self.mf = CardMF(profile=profile)
|
||||
self.card = card
|
||||
self.selected_file = self.mf # type: CardDF
|
||||
self.profile = profile
|
||||
@@ -1437,6 +1469,19 @@ class CardProfile(object):
|
||||
"""
|
||||
return interpret_sw(self.sw, sw)
|
||||
|
||||
def decode_select_response(self, data_hex:str) -> Any:
|
||||
"""Decode the response to a SELECT command.
|
||||
|
||||
This is the fall-back method which doesn't perform any decoding. It mostly
|
||||
exists so specific derived classes can overload it for actual decoding.
|
||||
This method is implemented in the profile and is only used when application
|
||||
specific decoding cannot be performed (no ADF is selected).
|
||||
|
||||
Args:
|
||||
data_hex: Hex string of the select response
|
||||
"""
|
||||
return data_hex
|
||||
|
||||
|
||||
class CardModel(abc.ABC):
|
||||
"""A specific card model, typically having some additional vendor-specific files. All
|
||||
|
||||
@@ -253,6 +253,3 @@ class DF_EIRENE(CardDF):
|
||||
EF_DialledVals(fid='6f87', name='EF.FreeNumber', desc='Free Number Call Type 0 and 8'),
|
||||
]
|
||||
self.add_files(files)
|
||||
|
||||
def decode_select_response(self, data_hex):
|
||||
return pySim.ts_51_011.decode_select_response(data_hex)
|
||||
|
||||
@@ -684,3 +684,6 @@ class CardProfileUICC(CardProfile):
|
||||
}
|
||||
|
||||
super().__init__('UICC', desc='ETSI TS 102 221', files_in_mf=files, sw=sw)
|
||||
|
||||
def decode_select_response(self, data_hex:str) -> Any:
|
||||
return decode_select_response(data_hex)
|
||||
|
||||
@@ -332,7 +332,6 @@ from pySim.construct import *
|
||||
import enum
|
||||
|
||||
from pySim.filesystem import *
|
||||
import pySim.ts_102_221
|
||||
|
||||
######################################################################
|
||||
# DF.TELECOM
|
||||
@@ -451,9 +450,6 @@ class DF_TELECOM(CardDF):
|
||||
]
|
||||
self.add_files(files)
|
||||
|
||||
def decode_select_response(self, data_hex):
|
||||
return decode_select_response(data_hex)
|
||||
|
||||
######################################################################
|
||||
# DF.GSM
|
||||
######################################################################
|
||||
@@ -936,13 +932,11 @@ class DF_GSM(CardDF):
|
||||
]
|
||||
self.add_files(files)
|
||||
|
||||
def decode_select_response(self, data_hex):
|
||||
return decode_select_response(data_hex)
|
||||
|
||||
def decode_select_response(resp_hex):
|
||||
|
||||
def _decode_select_response(resp_hex):
|
||||
|
||||
resp_bin = h2b(resp_hex)
|
||||
if resp_bin[0] == 0x62:
|
||||
return pySim.ts_102_221.decode_select_response(resp_hex)
|
||||
struct_of_file_map = {
|
||||
0: 'transparent',
|
||||
1: 'linear_fixed',
|
||||
@@ -983,3 +977,6 @@ def decode_select_response(resp_hex):
|
||||
class CardProfileSIM(CardProfile):
|
||||
def __init__(self):
|
||||
super().__init__('SIM', desc='GSM SIM Card', files_in_mf=[DF_TELECOM(), DF_GSM()])
|
||||
|
||||
def decode_select_response(self, data_hex:str) -> Any:
|
||||
return _decode_select_response(data_hex)
|
||||
|
||||
Reference in New Issue
Block a user