Add support for ADF_USIM/EF_EHPLMN
If the EF.EHPLMN exists, it contains the "Equivalent Home PLMN List". The odd part of that list is that it is not just a list of additional PLMN identities, but if the first digits of the IMSI are *not* listed in EF.EHPLMN, then the MCC/MNC of the IMSI prefix is suddently no longer considered the home network, but the subscriber is roaming. See TS 23.122: "If the HPLMN code derived from the IMSI is not present in the EHPLMN list, then it shall be treated as a Visited PLMN for PLMN selection purposes." Change-Id: I22d96ab4a424ec5bc1fb02f5e80165c646a748d3
This commit is contained in:
@@ -241,6 +241,13 @@ if __name__ == '__main__':
|
|||||||
# Check whether we have th AID of USIM, if so select it by its AID
|
# Check whether we have th AID of USIM, if so select it by its AID
|
||||||
# EF.UST - File Id in ADF USIM : 6f38
|
# EF.UST - File Id in ADF USIM : 6f38
|
||||||
if '9000' == card.select_adf_by_aid():
|
if '9000' == card.select_adf_by_aid():
|
||||||
|
# EF.EHPLMN
|
||||||
|
if card.file_exists(EF_USIM_ADF_map['EHPLMN']):
|
||||||
|
(res, sw) = card.read_ehplmn()
|
||||||
|
if sw == '9000':
|
||||||
|
print("EHPLMN:\n%s" % (res))
|
||||||
|
else:
|
||||||
|
print("EHPLMN: Can't read, response code = %s" % (sw,))
|
||||||
# EF.UST
|
# EF.UST
|
||||||
(res, sw) = card.read_binary(EF_USIM_ADF_map['UST'])
|
(res, sw) = card.read_binary(EF_USIM_ADF_map['UST'])
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from pySim.ts_51_011 import EF, DF
|
from pySim.ts_51_011 import EF, DF
|
||||||
|
from pySim.ts_31_102 import EF_USIM_ADF_map
|
||||||
from pySim.utils import *
|
from pySim.utils import *
|
||||||
from smartcard.util import toBytes
|
from smartcard.util import toBytes
|
||||||
|
|
||||||
@@ -41,6 +42,13 @@ class Card(object):
|
|||||||
print("warning: erasing is not supported for specified card type!")
|
print("warning: erasing is not supported for specified card type!")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def file_exists(self, fid):
|
||||||
|
res_arr = self._scc.try_select_file(fid)
|
||||||
|
for res in res_arr:
|
||||||
|
if res[1] != '9000':
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
def verify_adm(self, key):
|
def verify_adm(self, key):
|
||||||
'''
|
'''
|
||||||
Authenticate with ADM key
|
Authenticate with ADM key
|
||||||
@@ -262,6 +270,25 @@ class Card(object):
|
|||||||
len = self._scc.record_size(ef)
|
len = self._scc.record_size(ef)
|
||||||
self._scc.update_record(ef, rec_no, "ff" * len, force_len=False, verify=True)
|
self._scc.update_record(ef, rec_no, "ff" * len, force_len=False, verify=True)
|
||||||
|
|
||||||
|
class UsimCard(Card):
|
||||||
|
def __init__(self, ssc):
|
||||||
|
super(UsimCard, self).__init__(ssc)
|
||||||
|
|
||||||
|
def read_ehplmn(self):
|
||||||
|
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'])
|
||||||
|
if sw == '9000':
|
||||||
|
return (format_xplmn(res), sw)
|
||||||
|
else:
|
||||||
|
return (None, sw)
|
||||||
|
|
||||||
|
def update_ehplmn(self, mcc, mnc):
|
||||||
|
data = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'], length=None, offset=0)
|
||||||
|
size = len(data[0]) // 2
|
||||||
|
ehplmn = enc_plmn(mcc, mnc)
|
||||||
|
data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], ehplmn)
|
||||||
|
return sw
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class _MagicSimBase(Card):
|
class _MagicSimBase(Card):
|
||||||
"""
|
"""
|
||||||
@@ -552,7 +579,7 @@ class SysmoSIMgr1(GrcardSim):
|
|||||||
return None
|
return None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class SysmoUSIMgr1(Card):
|
class SysmoUSIMgr1(UsimCard):
|
||||||
"""
|
"""
|
||||||
sysmocom sysmoUSIM-GR1
|
sysmocom sysmoUSIM-GR1
|
||||||
"""
|
"""
|
||||||
@@ -653,7 +680,7 @@ class SysmoSIMgr2(Card):
|
|||||||
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
||||||
|
|
||||||
|
|
||||||
class SysmoUSIMSJS1(Card):
|
class SysmoUSIMSJS1(UsimCard):
|
||||||
"""
|
"""
|
||||||
sysmocom sysmoUSIM-SJS1
|
sysmocom sysmoUSIM-SJS1
|
||||||
"""
|
"""
|
||||||
@@ -1037,7 +1064,7 @@ class WavemobileSim(Card):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class SysmoISIMSJA2(Card):
|
class SysmoISIMSJA2(UsimCard):
|
||||||
"""
|
"""
|
||||||
sysmocom sysmoISIM-SJA2
|
sysmocom sysmoISIM-SJA2
|
||||||
"""
|
"""
|
||||||
@@ -1144,16 +1171,22 @@ class SysmoISIMSJA2(Card):
|
|||||||
if p.get('opc'):
|
if p.get('opc'):
|
||||||
self._scc.update_binary('af20', p['opc'], 17)
|
self._scc.update_binary('af20', p['opc'], 17)
|
||||||
|
|
||||||
# update EF-USIM_AUTH_KEY in ADF.USIM
|
|
||||||
self._scc.select_file(['3f00'])
|
self._scc.select_file(['3f00'])
|
||||||
aid = self.read_aid()
|
aid = self.read_aid()
|
||||||
if (aid):
|
if (aid):
|
||||||
|
# update EF-USIM_AUTH_KEY in ADF.USIM
|
||||||
self._scc.select_adf(aid)
|
self._scc.select_adf(aid)
|
||||||
if p.get('ki'):
|
if p.get('ki'):
|
||||||
self._scc.update_binary('af20', p['ki'], 1)
|
self._scc.update_binary('af20', p['ki'], 1)
|
||||||
if p.get('opc'):
|
if p.get('opc'):
|
||||||
self._scc.update_binary('af20', p['opc'], 17)
|
self._scc.update_binary('af20', p['opc'], 17)
|
||||||
|
|
||||||
|
# update EF.EHPLMN in ADF.USIM
|
||||||
|
if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
|
||||||
|
if p.get('mcc') and p.get('mnc'):
|
||||||
|
sw = self.update_ehplmn(p['mcc'], p['mnc'])
|
||||||
|
if sw != '9000':
|
||||||
|
print("Programming EHPLMN failed with code %s"%sw)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -100,6 +100,17 @@ class SimCardCommands(object):
|
|||||||
def sel_ctrl(self, value):
|
def sel_ctrl(self, value):
|
||||||
self._sel_ctrl = value
|
self._sel_ctrl = value
|
||||||
|
|
||||||
|
def try_select_file(self, dir_list):
|
||||||
|
rv = []
|
||||||
|
if type(dir_list) is not list:
|
||||||
|
dir_list = [dir_list]
|
||||||
|
for i in dir_list:
|
||||||
|
data, sw = self._tp.send_apdu(self.cla_byte + "a4" + self.sel_ctrl + "02" + i)
|
||||||
|
rv.append((data, sw))
|
||||||
|
if sw != '9000':
|
||||||
|
return rv
|
||||||
|
return rv
|
||||||
|
|
||||||
def select_file(self, dir_list):
|
def select_file(self, dir_list):
|
||||||
rv = []
|
rv = []
|
||||||
if type(dir_list) is not list:
|
if type(dir_list) is not list:
|
||||||
|
|||||||
@@ -125,6 +125,9 @@ def enc_spn(name, hplmn_disp=False, oplmn_disp=False):
|
|||||||
def hexstr_to_fivebytearr(s):
|
def hexstr_to_fivebytearr(s):
|
||||||
return [s[i:i+10] for i in range(0, len(s), 10) ]
|
return [s[i:i+10] for i in range(0, len(s), 10) ]
|
||||||
|
|
||||||
|
def hexstr_to_threebytearr(s):
|
||||||
|
return [s[i:i+6] for i in range(0, len(s), 6) ]
|
||||||
|
|
||||||
# Accepts hex string representing three bytes
|
# Accepts hex string representing three bytes
|
||||||
def dec_mcc_from_plmn(plmn):
|
def dec_mcc_from_plmn(plmn):
|
||||||
ia = h2i(plmn)
|
ia = h2i(plmn)
|
||||||
@@ -213,6 +216,25 @@ def dec_epsloci(hexstr):
|
|||||||
res['status'] = h2i(hexstr[34:36])
|
res['status'] = h2i(hexstr[34:36])
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def dec_xplmn(threehexbytes):
|
||||||
|
res = {'mcc': 0, 'mnc': 0, 'act': []}
|
||||||
|
plmn_chars = 6
|
||||||
|
plmn_str = threehexbytes[:plmn_chars] # first three bytes (six ascii hex chars)
|
||||||
|
res['mcc'] = dec_mcc_from_plmn(plmn_str)
|
||||||
|
res['mnc'] = dec_mnc_from_plmn(plmn_str)
|
||||||
|
return res
|
||||||
|
|
||||||
|
def format_xplmn(hexstr):
|
||||||
|
s = ""
|
||||||
|
for rec_data in hexstr_to_threebytearr(hexstr):
|
||||||
|
rec_info = dec_xplmn(rec_data)
|
||||||
|
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
|
||||||
|
rec_str = "unused"
|
||||||
|
else:
|
||||||
|
rec_str = "MCC: %03d MNC: %03d" % (rec_info['mcc'], rec_info['mnc'])
|
||||||
|
s += "\t%s # %s\n" % (rec_data, rec_str)
|
||||||
|
return s
|
||||||
|
|
||||||
def derive_milenage_opc(ki_hex, op_hex):
|
def derive_milenage_opc(ki_hex, op_hex):
|
||||||
"""
|
"""
|
||||||
Run the milenage algorithm to calculate OPC from Ki and OP
|
Run the milenage algorithm to calculate OPC from Ki and OP
|
||||||
|
|||||||
@@ -100,6 +100,12 @@ SIM Service Table: ff33ffff3f003f0f300cf0c3f00000
|
|||||||
Service 58 - Extension 8
|
Service 58 - Extension 8
|
||||||
Service 59 - MMS User Connectivity Parameters
|
Service 59 - MMS User Connectivity Parameters
|
||||||
|
|
||||||
|
EHPLMN:
|
||||||
|
00f110 # MCC: 001 MNC: 001
|
||||||
|
ffffff # unused
|
||||||
|
ffffff # unused
|
||||||
|
ffffff # unused
|
||||||
|
|
||||||
USIM Service Table: beff9f9de73e0408400170730000002e00000000
|
USIM Service Table: beff9f9de73e0408400170730000002e00000000
|
||||||
Service 2 - Fixed Dialling Numbers (FDN)
|
Service 2 - Fixed Dialling Numbers (FDN)
|
||||||
Service 3 - Extension 2
|
Service 3 - Extension 2
|
||||||
|
|||||||
Reference in New Issue
Block a user