aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--pySim/commands.py62
1 files changed, 56 insertions, 6 deletions
diff --git a/pySim/commands.py b/pySim/commands.py
index eba915c..9e16b0e 100644
--- a/pySim/commands.py
+++ b/pySim/commands.py
@@ -23,7 +23,7 @@
#
from pySim.utils import rpad, b2h
-
+from pytlv.TLV import *
class SimCardCommands(object):
def __init__(self, transport):
@@ -31,6 +31,56 @@ class SimCardCommands(object):
self._cla_byte = "a0"
self.sel_ctrl = "0000"
+ # Get file size from FCP
+ def __get_len_from_tlv(self, fcp):
+ # see also: ETSI TS 102 221, chapter 11.1.1.3.1 Response for MF,
+ # DF or ADF
+ tlvparser = TLV(['82', '83', '84', 'A5', '8a', '8b', '8c', '80', 'ab', 'c6', '81', '88'])
+
+ # pytlv is case sensitive!
+ fcp = fcp.lower()
+
+ if fcp[0:2] != '62':
+ raise ValueError('Tag of the FCP template does not match, expected 62 but got %s'%fcp[0:2])
+
+ # Unfortunately the spec is not very clear if the FCP length is
+ # coded as one or two byte vale, so we have to try it out by
+ # checking if the length of the remaining TLV string matches
+ # what we get in the length field.
+ # See also ETSI TS 102 221, chapter 11.1.1.3.0 Base coding.
+ exp_tlv_len = int(fcp[2:4], 16)
+ if len(fcp[4:])/2 == exp_tlv_len:
+ skip = 4
+ else:
+ exp_tlv_len = int(fcp[2:6], 16)
+ if len(fcp[4:])/2 == exp_tlv_len:
+ skip = 6
+
+ # Skip FCP tag and length
+ tlv = fcp[skip:]
+ tlv_parsed = tlvparser.parse(tlv)
+
+ return int(tlv_parsed['80'], 16)
+
+ # Tell the length of a record by the card response
+ # USIMs respond with an FCP template, which is different
+ # from what SIMs responds. See also:
+ # USIM: ETSI TS 102 221, chapter 11.1.1.3 Response Data
+ # SIM: GSM 11.11, chapter 9.2.1 SELECT
+ def __record_len(self, r):
+ if self.sel_ctrl == "0004":
+ return self.__get_len_from_tlv(r[-1])
+ else:
+ return int(r[-1][28:30], 16)
+
+ # Tell the length of a binary file. See also comment
+ # above.
+ def __len(self, r):
+ if self.sel_ctrl == "0004":
+ return self.__get_len_from_tlv(r[-1])
+ else:
+ return int(r[-1][4:8], 16)
+
def get_atr(self):
return self._tp.get_atr()
@@ -60,7 +110,7 @@ class SimCardCommands(object):
ef = [ef]
r = self.select_file(ef)
if length is None:
- length = int(r[-1][4:8], 16) - offset
+ length = self.__len(r) - offset
pdu = self.cla_byte + 'b0%04x%02x' % (offset, (min(256, length) & 0xff))
return self._tp.send_apdu(pdu)
@@ -75,7 +125,7 @@ class SimCardCommands(object):
if not hasattr(type(ef), '__iter__'):
ef = [ef]
r = self.select_file(ef)
- rec_length = int(r[-1][28:30], 16)
+ rec_length = self.__record_len(r)
pdu = self.cla_byte + 'b2%02x04%02x' % (rec_no, rec_length)
return self._tp.send_apdu(pdu)
@@ -84,7 +134,7 @@ class SimCardCommands(object):
ef = [ef]
r = self.select_file(ef)
if not force_len:
- rec_length = int(r[-1][28:30], 16)
+ rec_length = self.__record_len(r)
if (len(data)/2 != rec_length):
raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data)/2))
else:
@@ -94,11 +144,11 @@ class SimCardCommands(object):
def record_size(self, ef):
r = self.select_file(ef)
- return int(r[-1][28:30], 16)
+ return self.__record_len(r)
def record_count(self, ef):
r = self.select_file(ef)
- return int(r[-1][4:8], 16) // int(r[-1][28:30], 16)
+ return self.__len(r) // self.__record_len(r)
def run_gsm(self, rand):
if len(rand) != 32: