<p>dexter has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/9597">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">commands: get file/record length from FCP (USIM)<br><br>Some of the methods SimCardCommands() have ways to determaine length<br>information from the card response. Regular sims use a format where<br>the length field is on a fixed position. USIMs use FCP templates<br>(format control parameters), which is a TLV encodecs string. So lets<br>distingish if we deal with an USIM (We can easily do this by looking<br>at the select control parameters) and extract the length info from<br>the FCP.<br><br>- If we deal with USIMs, use the FCP to determine length<br>  information<br><br>Change-Id: I068cf8a532e1c79a2d208e9d275c155ddb72713c<br>Related: SYS#4245<br>---<br>M pySim/commands.py<br>1 file changed, 56 insertions(+), 6 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/97/9597/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/pySim/commands.py b/pySim/commands.py</span><br><span>index eba915c..9e16b0e 100644</span><br><span>--- a/pySim/commands.py</span><br><span>+++ b/pySim/commands.py</span><br><span>@@ -23,7 +23,7 @@</span><br><span> #</span><br><span> </span><br><span> from pySim.utils import rpad, b2h</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+from pytlv.TLV import *</span><br><span> </span><br><span> class SimCardCommands(object):</span><br><span>        def __init__(self, transport):</span><br><span>@@ -31,6 +31,56 @@</span><br><span>          self._cla_byte = "a0"</span><br><span>              self.sel_ctrl = "0000"</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+  # Get file size from FCP</span><br><span style="color: hsl(120, 100%, 40%);">+      def __get_len_from_tlv(self, fcp):</span><br><span style="color: hsl(120, 100%, 40%);">+            # see also: ETSI TS 102 221, chapter 11.1.1.3.1 Response for MF,</span><br><span style="color: hsl(120, 100%, 40%);">+              # DF or ADF</span><br><span style="color: hsl(120, 100%, 40%);">+           tlvparser = TLV(['82', '83', '84', 'A5', '8a', '8b', '8c', '80', 'ab', 'c6', '81', '88'])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           # pytlv is case sensitive!</span><br><span style="color: hsl(120, 100%, 40%);">+            fcp = fcp.lower()</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if fcp[0:2] != '62':</span><br><span style="color: hsl(120, 100%, 40%);">+                  raise ValueError('Tag of the FCP template does not match, expected 62 but got %s'%fcp[0:2])</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         # Unfortunately the spec is not very clear if the FCP length is</span><br><span style="color: hsl(120, 100%, 40%);">+               # coded as one or two byte vale, so we have to try it out by</span><br><span style="color: hsl(120, 100%, 40%);">+          # checking if the length of the remaining TLV string matches</span><br><span style="color: hsl(120, 100%, 40%);">+          # what we get in the length field.</span><br><span style="color: hsl(120, 100%, 40%);">+            # See also ETSI TS 102 221, chapter 11.1.1.3.0 Base coding.</span><br><span style="color: hsl(120, 100%, 40%);">+           exp_tlv_len = int(fcp[2:4], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+               if len(fcp[4:])/2 == exp_tlv_len:</span><br><span style="color: hsl(120, 100%, 40%);">+                     skip = 4</span><br><span style="color: hsl(120, 100%, 40%);">+              else:</span><br><span style="color: hsl(120, 100%, 40%);">+                 exp_tlv_len = int(fcp[2:6], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+                       if len(fcp[4:])/2 == exp_tlv_len:</span><br><span style="color: hsl(120, 100%, 40%);">+                             skip = 6</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+            # Skip FCP tag and length</span><br><span style="color: hsl(120, 100%, 40%);">+             tlv = fcp[skip:]</span><br><span style="color: hsl(120, 100%, 40%);">+              tlv_parsed = tlvparser.parse(tlv)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           return int(tlv_parsed['80'], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # Tell the length of a record by the card response</span><br><span style="color: hsl(120, 100%, 40%);">+        # USIMs respond with an FCP template, which is different</span><br><span style="color: hsl(120, 100%, 40%);">+        # from what SIMs responds. See also:</span><br><span style="color: hsl(120, 100%, 40%);">+        # USIM: ETSI TS 102 221, chapter 11.1.1.3 Response Data</span><br><span style="color: hsl(120, 100%, 40%);">+        # SIM: GSM 11.11, chapter 9.2.1 SELECT</span><br><span style="color: hsl(120, 100%, 40%);">+       def __record_len(self, r):</span><br><span style="color: hsl(120, 100%, 40%);">+                if self.sel_ctrl == "0004":</span><br><span style="color: hsl(120, 100%, 40%);">+                        return self.__get_len_from_tlv(r[-1])</span><br><span style="color: hsl(120, 100%, 40%);">+                else:</span><br><span style="color: hsl(120, 100%, 40%);">+                        return int(r[-1][28:30], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        # Tell the length of a binary file. See also comment</span><br><span style="color: hsl(120, 100%, 40%);">+        # above.</span><br><span style="color: hsl(120, 100%, 40%);">+       def __len(self, r):</span><br><span style="color: hsl(120, 100%, 40%);">+                if self.sel_ctrl == "0004":</span><br><span style="color: hsl(120, 100%, 40%);">+                        return self.__get_len_from_tlv(r[-1])</span><br><span style="color: hsl(120, 100%, 40%);">+                else:</span><br><span style="color: hsl(120, 100%, 40%);">+                        return int(r[-1][4:8], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       def get_atr(self):</span><br><span>           return self._tp.get_atr()</span><br><span> </span><br><span>@@ -60,7 +110,7 @@</span><br><span>                   ef = [ef]</span><br><span>            r = self.select_file(ef)</span><br><span>             if length is None:</span><br><span style="color: hsl(0, 100%, 40%);">-                      length = int(r[-1][4:8], 16) - offset</span><br><span style="color: hsl(120, 100%, 40%);">+                 length = self.__len(r) - offset</span><br><span>              pdu = self.cla_byte + 'b0%04x%02x' % (offset, (min(256, length) & 0xff))</span><br><span>                 return self._tp.send_apdu(pdu)</span><br><span> </span><br><span>@@ -75,7 +125,7 @@</span><br><span>              if not hasattr(type(ef), '__iter__'):</span><br><span>                        ef = [ef]</span><br><span>            r = self.select_file(ef)</span><br><span style="color: hsl(0, 100%, 40%);">-                rec_length = int(r[-1][28:30], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+            rec_length = self.__record_len(r)</span><br><span>            pdu = self.cla_byte + 'b2%02x04%02x' % (rec_no, rec_length)</span><br><span>          return self._tp.send_apdu(pdu)</span><br><span> </span><br><span>@@ -84,7 +134,7 @@</span><br><span>                      ef = [ef]</span><br><span>            r = self.select_file(ef)</span><br><span>             if not force_len:</span><br><span style="color: hsl(0, 100%, 40%);">-                       rec_length = int(r[-1][28:30], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+                    rec_length = self.__record_len(r)</span><br><span>                    if (len(data)/2 != rec_length):</span><br><span>                              raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data)/2))</span><br><span>            else:</span><br><span>@@ -94,11 +144,11 @@</span><br><span> </span><br><span>     def record_size(self, ef):</span><br><span>           r = self.select_file(ef)</span><br><span style="color: hsl(0, 100%, 40%);">-                return int(r[-1][28:30], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+          return self.__record_len(r)</span><br><span> </span><br><span>      def record_count(self, ef):</span><br><span>          r = self.select_file(ef)</span><br><span style="color: hsl(0, 100%, 40%);">-                return int(r[-1][4:8], 16) // int(r[-1][28:30], 16)</span><br><span style="color: hsl(120, 100%, 40%);">+           return self.__len(r) // self.__record_len(r)</span><br><span> </span><br><span>     def run_gsm(self, rand):</span><br><span>             if len(rand) != 32:</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/9597">change 9597</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/9597"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: pysim </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I068cf8a532e1c79a2d208e9d275c155ddb72713c </div>
<div style="display:none"> Gerrit-Change-Number: 9597 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>