[PATCH] osmo-sim-auth[master]: SIM API's to fetch information from SIM file system like Kc, ...

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

Gerard gerrit-no-reply at lists.osmocom.org
Sat Jun 3 07:40:01 UTC 2017


Review at  https://gerrit.osmocom.org/2833

SIM API's to fetch information from SIM file system like Kc, LOCI, MSISDN etc. Added -p option for fetching SIM information based on the parameter passed.

Change-Id: I1f43ff918a6b96f86e661297e84010e6cdf17b84
---
M card/SIM.py
M osmo-sim-auth.py
2 files changed, 335 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/osmo-sim-auth refs/changes/33/2833/1

diff --git a/card/SIM.py b/card/SIM.py
index 1ad45e3..5d97ba4 100644
--- a/card/SIM.py
+++ b/card/SIM.py
@@ -29,6 +29,7 @@
 from card.ICC import ISO7816
 from card.FS import SIM_FS
 from card.utils import *
+from binascii import *
 
 
 class SIM(ISO7816):
@@ -50,6 +51,18 @@
             print '[DBG] type definition: %s' % type(self)
             print '[DBG] CLA definition: %s' % hex(self.CLA)
         
+        self.caller = {
+        'KC' : self.get_Kc,
+        'IMSI' : self.get_imsi,
+        'LOCI' : self.get_loci,
+        'HPPLMN' : self.get_hpplmn,
+        'PLMN_SEL' : self.get_plmnsel,
+        'ACC' : self.get_acc,
+        'ICCID' : self.get_iccid,
+        'FPLMN' : self.get_fplmn,
+        'MSISDN' : self.get_msisdn,
+        'SMSP' : self.get_smsp,
+        }
     
     def sw_status(self, sw1, sw2):
         '''
@@ -264,11 +277,317 @@
         
         # and parse the received data into the IMSI structure
         if 'Data' in imsi.keys() and len(imsi['Data']) == 9:
+
+            if self.dbg:
+                print "[DBG] International Mobile Subscriber Identity (IMSI): %s " % decode_BCD(imsi['Data'])[3:]
+
             return decode_BCD(imsi['Data'])[3:]
         
         # if issue with the content of the DF_IMSI file
         if self.dbg: 
             print '[DBG] %s' % self.coms()
         return None
+
+    # This contains Ciphering Key for GSM
+    # File Size = 9 bytes
+    # select Kc to get Kc (1-8 bytes) and
+    # cihering key sequence number (9th byte)
+    # returns bytes Kc on success or None on error
+    def get_Kc(self):
+        self.select([0x7F, 0x20])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        Kc = self.select([0x6F, 0x20])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in Kc.keys() and len(Kc['Data']) == 9:
+            if self.dbg:
+                print "[DBG] Ciphering Key (Kc): %s" % b2a_hex(byteToString(Kc['Data'][0:8]))
+                print "[DBG] Ciphering Key Sequence Number (n): %s " % Kc['Data'][8]
+            return Kc['Data']
+        else:
+            return None
     
+    # EF loci contains location information
+    # This conatins TMSI, LAI, TMSI TIME, and Location update status
+    # and prints the information
+    # File Size = 11 bytes
+    # select LOCI to get TMSI(1-4 bytes), LAI(5-9 bytes), TMSI TIME (10th byte)
+    # LOCI includes Mobile country code (MCC), Mobile network code (MNC),
+    # and Locatio area code (LAC)
+    # and location update status (11th byte)
+    # returns bytes LOCI on success or None on error
+    def get_loci(self):
+        self.select([0x7F, 0x20])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        loci = self.select([0x6F, 0x7E])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in loci.keys() and len(loci['Data']) == 11:
+            loci = loci['Data']
+
+            if self.dbg:
+                print "[DBG] Temporary Mobile Subscriber Identity (TMSI): %s" % b2a_hex(byteToString(loci[0:4]))
+                LAI = loci[4:9]
+                print "[DBG] Location Area Identity hex (LAI): %s" % b2a_hex(byteToString(LAI))
+                MCC = ((LAI[0] & 0x0f) << 8) | (LAI[0] & 0xf0) | (LAI[1] & 0x0f)
+                MNC = ((LAI[2] & 0x0f) << 8) | (LAI[2] & 0xf0) | ((LAI[1] & 0xf0) >> 4)
+                LAC = LAI[3:5]
+                print "[DBG] Mobile Country Code (MCC): %s " % format(int(hex(MCC),16),"x")
+                print "[DBG] Mobile Country Code (MNC): %s " % format(int(hex(MNC),16),"x")
+                print "[DBG] Location Area Code (LAC): %s " % b2a_hex(byteToString(LAC))
+                print "[DBG] TMSI TIME: %s" % loci[9]
+                print "[DBG] Location Update Status: %s" % loci[10]
+
+            return loci
+        else:
+            return None
+
+    # EF plmnsel contains Public Land Mobile Network records
+    # File Size: 3n (n >=8)
+    # Contents Mobile country code (MCC) & Mobile Netwokr code (MNC) (total 3 bytes)
+    # excess bytes set to 'FF'
+    # returns bytes PLMNSel on success or None on error
+    def get_plmnsel(self):
+        self.select([0x7F, 0x20])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        plmnsel = self.select([0x6F, 0x30])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in plmnsel.keys():
+            plmnsel = plmnsel['Data']
+
+            if self.dbg:
+                print "[DBG] Stored PLMN selector:\tMCC | MNC\n"
+                index = 0
+                while len(plmnsel) > 3 and index < len(plmnsel):
+                    if plmnsel[index] == 0xFF and plmnsel[index+1] == 0xFF and plmnsel[index+2] == 0xFF:
+                        break
+                    else:
+                        MCC = ((plmnsel[index] & 0x0f) << 8) | (plmnsel[index] & 0xf0) | (plmnsel[index+1] & 0x0f)
+                        MNC = ((plmnsel[index+2] & 0x0f) << 8) | (plmnsel[index+2] & 0xf0) | ((plmnsel[index+1] & 0xf0) >> 4)
+                        if (MNC & 0x000f) == 0x000f:
+                            MNC = MNC >> 4
+                            print "[DBG] \t\t\t\t%03x   %02x" %(MCC, MNC)
+                        else:
+                            print "[DBG] \t\t\t\t%03x   %03x" %(MCC, MNC)
+                        index +=3
+
+            return plmnsel
+        else:
+            return None
+
+    # select DF_GSM for Higher Priority PLMN search period
+    # File Size: 1 byte
+    # Contains the interval of time between searches for a higher priority PLMN
+    # 'YZ': (16Y + Z) minutes
+    # returns byte on success or None on error
+    def get_hpplmn(self):
+        self.select([0x7F, 0x20])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        hpplmn = self.select([0x6F, 0x31])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in hpplmn.keys() and len(hpplmn['Data']) == 1:
+            hpplmn = hpplmn['Data']
+
+            if self.dbg:
+                if hpplmn[0] < 9:
+                    print "[DBG] Higher Priority PLMN search period %s min" % hpplmn[0]
+                else:
+                    hpplmn_val = list(str(hpplmn[0]))
+                    interval = (16 * int(hpplmn_val[0])) + int(hpplmn_val[1])
+                    print "[DBG] Higher Priority PLMN search period %s min" % interval
+
+            return hpplmn
+        else:
+            return None
+
+    # select DF_GSM for accessing Access control class
+    # The access control class is a parameter to control the RACH utilization
+    # File Size = 2 bytes
+    # returns byte on success or None on error
+    def get_acc(self):
+        self.select([0x7F, 0x20])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        acc = self.select([0x6F, 0x78])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in acc.keys() and len(acc['Data']) == 2:
+            acc = acc['Data']
+
+            if self.dbg:
+                print "[DBG] Access Control Classes %s " % b2a_hex(byteToString(acc))
+
+            return acc
+        else:
+            return None
+
+    # select DF_TELECOM for Mobile Station Integrated Services Digital Network (MSISDN)
+    # Record Length: X + 14 bytes
+    # Type of number (TON 4 bits) and numbering plan identification (NPI 3 bits) 8th bt is always 1 = 1 byte
+    # Dialling Number aka Calling Number
+    # returns an array of msisdn's or None on error
+    def get_msisdn(self):
+        self.select([0x7F, 0x10])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        msisdn = self.select([0x6F, 0x40])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in msisdn.keys():
+            msisdns = msisdn['Data']
+
+            if self.dbg:
+                for msisdn in msisdns:
+                    rec_length = len(msisdn) - 14
+                    len_bcd_number = msisdn[rec_length]
+
+                    TON_NPI = msisdn[rec_length + 1 : rec_length + 2][0]
+                    npi = TON_NPI & 0x0F
+                    ton  = (TON_NPI >> 4) & 0x07
+                    print "[DBG] Type of number (TON): %s " % ton
+                    print "[DBG] Numbering plan identification (NPI): %s " % npi
+
+                    dialing_number = msisdn[rec_length + 2 : rec_length + len_bcd_number + 1]
+                    print "[DBG] Dialling Number: %s " % decode_BCD(dialing_number)[:-2]
+
+            return msisdns
+        else:
+            return None
+
+    # Short Message Service Parameters (SMSP)
+    # select DF_TELECOM for SIM card = 0x7f10
+    # Used preparation of mobile originated short messages
+    # It holds the settings for sending text message
+    # File Size = (28 + n) bytes
+    # returns an array of smsps or None on error
+    def get_smsp(self):
+        self.select([0x7F, 0x10])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        smsp = self.select([0x6F, 0x42])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in smsp.keys():
+            smsps = smsp['Data']
+
+            if self.dbg:
+                for smsp in smsps:
+                    rec_length = len(smsp) - 28
+                    rec_len = smsp[rec_length+13]
+                    service_center_address = decode_BCD(smsp[rec_length+15:rec_length+rec_len + 14])[:-2]
+                    print "[DBG] TP-Service Centre Address: %s " % service_center_address
+
+            return smsps
+        else:
+            return None
+
+    # This EF contains 4 Forbidden PLMN 3 bytes each
+    # File Size 12 bytes
+    # Unused bytes are set to 'FF'
+    # returns byte on success or None on error
+    def get_fplmn(self):
+        self.select([0x7F, 0x20])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        fplmn = self.select([0x6F, 0x7b])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in fplmn.keys() and len(fplmn['Data']) == 12:
+            fplmn = fplmn['Data']
+
+            if self.dbg:
+                print "[DBG] Stored FPLMN selector:\tMCC | MNC\n"
+                index = 0
+                while len(fplmn) > 3 and index < len(fplmn):
+                    if fplmn[index] == 0xFF and fplmn[index+1] == 0xFF and fplmn[index+2] == 0xFF:
+                        break
+                    else:
+                        MCC = ((fplmn[index] & 0x0f) << 8) | (fplmn[index] & 0xf0) | (fplmn[index+1] & 0x0f)
+                        MNC = ((fplmn[index+2] & 0x0f) << 8) | (fplmn[index+2] & 0xf0) | ((fplmn[index+1] & 0xf0) >> 4)
+                        if (MNC & 0x000f) == 0x000f:
+                            MNC = MNC >> 4
+                            print "[DBG] \t\t\t\t%03x   %02x" %(MCC, MNC)
+                        else:
+                            print "[DBG] \t\t\t\t%03x   %03x" %(MCC, MNC)
+                        index +=3
+
+
+            return fplmn
+        else:
+            return None
+
+    # This file holds a unique smart card identification number.
+    # file Size = 10 bytes (BCD encoded)
+    # Left justified and right-padded with 'F'
+    # returns bytes on success or None on error
+    def get_iccid(self):
+        iccid = self.select([0x2F, 0xE2])
+        if self.coms()[2] != (0x90, 0x00):
+            if self.dbg:
+                print '[DBG] %s' % self.coms()
+            return None
+
+        if 'Data' in iccid.keys() and len(iccid['Data']) == 10:
+            iccid = iccid['Data']
+
+            if self.dbg:
+                print "[DBG] identification (ICCID): %s" % decode_BCD(iccid)
+
+            return iccid
+        else:
+            return None
 
diff --git a/osmo-sim-auth.py b/osmo-sim-auth.py
index 29e0226..89deac4 100755
--- a/osmo-sim-auth.py
+++ b/osmo-sim-auth.py
@@ -78,6 +78,16 @@
 	if options.ipsec:
 		print "1%s at uma.mnc%s.mcc%s.3gppnetwork.org,%s,%s,%s" % (imsi, imsi[3:6], imsi[0:3], b2a_hex(byteToString(rand_bin)), b2a_hex(byteToString(ret[0])), b2a_hex(byteToString(ret[1])))
 
+def handle_sim_info(options):
+	s= SIM()
+	if not s:
+		print "Error opening SIM"
+		exit(1)
+
+	if options.debug:
+		s.dbg = 1
+
+	s.caller.get(options.param)()
 
 if __name__ == "__main__":
 	parser = OptionParser()
@@ -94,9 +104,15 @@
 	parser.add_option("-I", "--ipsec", dest="ipsec",
 			  help="IPSEC mode for strongswan triplets.dat",
 			  action="store_true")
+	parser.add_option("-p", "--param", dest="param",
+			  help="Retrieve SIM card parameter (mode: SIM) KC|IMSI|LOCI|HPPLMN|PLMN_SEL|ICCID|ACC|FPLMN|MSISDN|SMSP")
 
 	(options, args) = parser.parse_args()
 
+	if options.param:
+		handle_sim_info(options)
+		exit(2)
+
 	if not options.rand:
 		print "You have to specify RAND"
 		exit(2)

-- 
To view, visit https://gerrit.osmocom.org/2833
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1f43ff918a6b96f86e661297e84010e6cdf17b84
Gerrit-PatchSet: 1
Gerrit-Project: osmo-sim-auth
Gerrit-Branch: master
Gerrit-Owner: Gerard <gerardfly9 at gmail.com>



More information about the gerrit-log mailing list