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.orgReview 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>