1 Commits

Author SHA1 Message Date
Harald Welte
46bc6d25d6 HACK: support for SIM factory file formats
Change-Id: I23cd37fc06b6e2d21964fd4f2694d9ee3c6012d4
2020-09-15 10:47:45 +02:00
26 changed files with 516 additions and 813 deletions

View File

@@ -40,8 +40,8 @@ pysim requires:
Example for Debian: Example for Debian:
apt-get install python3-pyscard python3-serial python3-pip python3-yaml apt-get install python-pyscard python-serial python-pip
pip3 install pytlv pip install pytlv
Mailing List Mailing List

View File

@@ -9,7 +9,7 @@ if [ ! -d "./pysim-testdata/" ] ; then
exit 1 exit 1
fi fi
virtualenv -p python3 venv --system-site-packages virtualenv -p python2 venv --system-site-packages
. venv/bin/activate . venv/bin/activate
pip install pytlv pip install pytlv
pip install pyyaml pip install pyyaml

141
execute_ipr.py Executable file
View File

@@ -0,0 +1,141 @@
#!/usr/bin/python3
from pySim.transport.pcsc import PcscSimLink
from pySim.utils import enc_iccid, enc_imsi
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException
from smartcard.System import readers
from lark import Lark, Transformer, Token, Tree
import sys
from format_ipr import ScriptFormatIPR
class DataTransform():
''' Transform raw/logical input data into the format use on the SIM card,
like encoding the PIN from '1234' -> 3132334 or IMSI encoding'''
def transform(self, inp):
outp = {}
for k in inp.keys():
f = getattr(self, 'xfrm_'+k, None)
if f != None:
outp[k] = f(inp[k])
else:
outp[k] = inp[k]
return outp
def xfrm_PIN(self, pin):
ret = ''
for c in str(pin):
ret += '3%c' % c
return ret
def xfrm_PIN1(self, pin):
return self.xfrm_PIN(pin)
def xfrm_PIN2(self, pin):
return self.xfrm_PIN(pin)
def xfrm_PUK1(self, pin):
return self.xfrm_PIN(pin)
def xfrm_PUK2(self, pin):
return self.xfrm_PIN(pin)
def xfrm_ADM1(self, pin):
return self.xfrm_PIN(pin)
def xfrm_ADM2(self, pin):
return self.xfrm_PIN(pin)
def xfrm_IMSI(self, imsi):
return enc_imsi(imsi)
def xfrm_ICCID(self, iccid):
# TODO: calculate luhn check digit
return enc_iccid(iccid)
def expand_cmd_template(cmd, templates):
''' Take a single command, supstituting all [] template keys with data from 'template' '''
ret = ""
for e in cmd:
if e[0] == 'hexstr':
ret += e[1]
if e[0] == 'key':
ret += templates[e[1]]
return ret
def match_sw(actual_sw, sw_match):
''' Check if actual_sw matches any of the templates given in sw_match'''
def match_sw_single(actual_sw, match):
match = match.lower()
if 'x' in match:
FIXME
else:
if actual_sw.lower() == match:
return True
return False
if sw_match == []:
return True
for m in sw_match:
if match_sw_single(actual_sw, m):
return True
return False
def execute_ipr_raw(s, sl, dynamic_data_raw = {}):
""" translate a single LDR statement to IPR format. """
if s == None:
None
elif s == 'reset':
print("RESET")
sl.reset_card()
elif s[0] == 'rem':
print("REM %s" % (s[1]))
elif s[0] == 'cmd':
d = s[1]
req = expand_cmd_template(d['req'], dynamic_data_raw)
rsp = d['rsp']
print("\tREQ: %s, EXP: %s" % (req, rsp))
(data, sw) = sl.send_apdu_raw(req)
if not match_sw(sw, rsp):
raise ValueError("SW %s doesn't match expected %s" % (sw, rsp))
print("\tRSP: %s\n" % (sw))
def execute_ipr(s, sl, dynamic_data = {}):
""" translate a single LDR statement to IPR format; optionally substitute dynamic_data. """
xf = DataTransform()
return execute_ipr_raw(s, sl, xf.transform(dynamic_data))
'''Dictionaries like this must be generated for each card to be programmed'''
demo_dict = {
'PIN1': '1234',
'PIN2': '1234',
'PUK1': '12345678',
'PUK2': '12345678',
'ADM1': '11111111',
'KIC1': '100102030405060708090a0b0c0d0e0f',
'KID1': '101102030405060708090a0b0c0d0e0f',
'KIK1': '102102030405060708090a0b0c0d0e0f',
'KIC2': '200102030405060708090a0b0c0d0e0f',
'KID2': '201102030405060708090a0b0c0d0e0f',
'KIK2': '202102030405060708090a0b0c0d0e0f',
'KIC3': '300102030405060708090a0b0c0d0e0f',
'KID3': '301102030405060708090a0b0c0d0e0f',
'KIK3': '302102030405060708090a0b0c0d0e0f',
'ICCID': '012345678901234567',
'IMSI': '001010123456789',
'ACC': '0200',
'KI': '000102030405060708090a0b0c0d0e0f',
'OPC': '101112131415161718191a1b1c1d1e1f',
'VERIFY_ICCID': '0001020304050608090a0b0c0d0e0f',
}
sl = PcscSimLink(0)
infile_name = sys.argv[1]
fmt = ScriptFormatIPR()
fmt.parse_process_file(infile_name, execute_ipr, {'sl':sl, 'dynamic_data':demo_dict})

55
format_ipr.py Normal file
View File

@@ -0,0 +1,55 @@
from lark import Lark, Transformer, Token, Tree
from script_format import ScriptFormat
from format_ldr import LdrXfrm
class IprXfrm(LdrXfrm):
""" transform the parse tree into a more easily consumable form """
def key(self, items):
return ('key', ''.join(list(items)))
def req(self, items):
return items[:-1]
def rsp(self, items):
return items[:-1]
#def NEWLINE(self, items):
#return None
class ScriptFormatIPR(ScriptFormat):
# parser for the IPR file format as used by the SIM card factory
ipr_parser = Lark(r"""
script: statement*
?statement: cmd | rst | rem | NEWLINE
NONL: /[^\n]/+
rem: "//" NONL? NEWLINE
ALNUM: DIGIT | LETTER | "_"
key: "[" ALNUM+ "]"
cmd: req rsp
req: "I:" [hexstr|key]+ NEWLINE
hexstr: HEX_ITEM+
HEX_ITEM: HEXDIGIT ~ 2
rsp: "O:" swpattern? NEWLINE
swpattern: HEX_OR_X ~ 4
HEX_OR_X: HEXDIGIT | "X" | "x"
rst: "RESET" NEWLINE
%import common.ESCAPED_STRING -> STRING
%import common.WS_INLINE
%import common.HEXDIGIT
%import common.DIGIT
%import common.LETTER
%import common.NEWLINE
%ignore WS_INLINE
""", start='script', parser='lalr')#, lexer='standard')
def parse_xform(self, text):
tree = self.ipr_parser.parse(text)
#print(tree.pretty())
p = IprXfrm().transform(tree)
return p

74
format_ldr.py Normal file
View File

@@ -0,0 +1,74 @@
from lark import Lark, Transformer, Token, Tree
from script_format import ScriptFormat
class LdrXfrm(Transformer):
""" transform the parse tree into a more easily consumable form """
def rst(self, items):
return ('reset')
def NONL(self, items):
return ''.join([i for i in items.value])
def rem(self, items):
return ('rem', items[0])
def swmatch(self, items):
return ('swmatch', items)
def cmd(self, items):
return ('cmd', {'req': items[0], 'rsp': items[1]})
def todigit(self, item):
""" convert from Token/Tree to raw hex-digit """
if isinstance(item, Token):
return item.value
elif isinstance(item, Tree):
return item.data
def hex_item(self, items):
""" return one byte as two-digit HEX string """
return "%s%s" % (items[0].value, items[1].value)
def hexstr(self, items):
""" return list of two-digit HEX strings """
return ('hexstr', ''.join(list(items)))
def swpattern(self, items):
""" return list of four HEX nibbles (or 'x' as wildcard) """
arr = [self.todigit(x) for x in items]
return ''.join(arr)
class ScriptFormatLDR(ScriptFormat):
# parser for the LDR file format as generated by Simulity Profile Editor
ldr_parser = Lark(r"""
script: statement*
?statement: cmd | rst | rem | NEWLINE
BSLASH: "\\\n"
%ignore BSLASH
NONL: /[^\n]/+
rem: "REM" NONL? NEWLINE
ALNUM: DIGIT | LETTER | "_"
key: "[" ALNUM+ "]"
cmd: "CMD" hexstr [swmatch] NEWLINE
cmd_item: hexstr | key
hexstr: hex_item+
hex_item: HEXDIGIT HEXDIGIT
swmatch: "(" swpattern ("," swpattern)* ")"
swpattern: hex_or_x hex_or_x hex_or_x hex_or_x
?hex_or_x: HEXDIGIT | "X" -> x | "x" -> x
rst: "RST" NEWLINE
%import common.ESCAPED_STRING -> STRING
%import common.WS_INLINE
%import common.HEXDIGIT
%import common.DIGIT
%import common.LETTER
%import common.NEWLINE
%ignore WS_INLINE
""", start='script')
def parse_xform(self, text):
tree = self.ldr_parser.parse(text)
#print(tree.pretty())
p = LdrXfrm().transform(tree)
return p

84
ldr_to_ipr.py Executable file
View File

@@ -0,0 +1,84 @@
#!/usr/bin/python3
from lark import Lark, Transformer, Token, Tree
import sys
from format_ldr import ScriptFormatLDR
from format_ipr import ScriptFormatIPR
def split_hex(value):
""" split a string of hex digits into groups (bytes) of two digits. """
return ' '.join(value[i:i+2] for i in range(0, len(value), 2))
def expand_cmd(cmd):
ret = ""
for e in cmd:
if e[0] == 'hexstr':
ret += e[1]
else:
raise ValueError("Unsupported '%s'" % (e[0]))
return ret
def ldr_stmt_to_ipr(s):
""" translate a single LDR statement to IPR format. """
if s == None:
None
elif s == 'reset':
print("RESET")
print("")
elif s[0] == 'rem':
print("//\t%s" % s[1])
elif s[0] == 'cmd':
cmd = s[1]
req = cmd['req']
rsp = cmd['rsp']
print("I: %s" % split_hex(expand_cmd([req])))
if rsp != None and len(rsp) != 1:
if rsp[0] != 'swmatch' or len(rsp[1]) != 1:
raise ValueError("Unsupported '%s'" % (rsp))
print("O: %s" % rsp[1][0])
else:
print("O:")
print("")
else:
print("Unknown %s" % (s.pretty()))
raise ValueError()
test_text = '''
RST
CMD E0 CA DF 1F 13
CMD E0 CA DF 1F (90 00)
CMD E0 CA DF 1F (61 XX, 90 00)
REM foo bar
CMD E4 DA DF 20 09 EA 53 F8 D7 64 1E D9 88 00 \\
(90 00 , 6B 00)
'''
def run_statement(s):
print(s)
def fii(s):
if s.data == 'rst':
print("=> RESET")
# FIXME: actually perform card reset
elif s.data == 'rem':
print(s)
elif s.data == 'cmd':
#print(s)
cmd = s.children[0]
print(s.pretty())
# FIXME: if swmatch: match all contained swpattern
else:
print("Unknown %s" % (s.pretty()))
raise ValueError()
#process_ldr(test_text, run_statement)
#process_ldr(test_text, ldr_stmt_to_ipr)
fmt = ScriptFormatLDR()
fmt.parse_process_file(sys.argv[1], ldr_stmt_to_ipr)
#fmt.parse_process_file(sys.argv[1], run_statement)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python2
# #
# Utility to deal with sim cards and program the 'magic' ones easily # Utility to deal with sim cards and program the 'magic' ones easily
@@ -147,24 +147,6 @@ def parse_options():
parser.add_option("--acc", dest="acc", parser.add_option("--acc", dest="acc",
help="Set ACC bits (Access Control Code). not all card types are supported", help="Set ACC bits (Access Control Code). not all card types are supported",
) )
parser.add_option("--epdgid", dest="epdgid",
help="Set Home Evolved Packet Data Gateway (ePDG) Identifier. (Only FQDN format supported)",
)
parser.add_option("--epdgSelection", dest="epdgSelection",
help="Set PLMN for ePDG Selection Information. (Only Operator Identifier FQDN format supported)",
)
parser.add_option("--pcscf", dest="pcscf",
help="Set Proxy Call Session Control Function (P-CSCF) Address. (Only FQDN format supported)",
)
parser.add_option("--ims-hdomain", dest="ims_hdomain",
help="Set IMS Home Network Domain Name in FQDN format",
)
parser.add_option("--impi", dest="impi",
help="Set IMS private user identity",
)
parser.add_option("--impu", dest="impu",
help="Set IMS public user identity",
)
parser.add_option("--read-imsi", dest="read_imsi", action="store_true", parser.add_option("--read-imsi", dest="read_imsi", action="store_true",
help="Read the IMSI from the CARD", default=False help="Read the IMSI from the CARD", default=False
) )
@@ -240,9 +222,8 @@ def parse_options():
def _digits(secret, usage, len, num): def _digits(secret, usage, len, num):
seed = secret + usage + '%d' % num s = hashlib.sha1(secret + usage + '%d' % num)
s = hashlib.sha1(seed.encode()) d = ''.join(['%02d'%ord(x) for x in s.digest()])
d = ''.join(['%02d' % x for x in s.digest()])
return d[0:len] return d[0:len]
def _mcc_mnc_digits(mcc, mnc): def _mcc_mnc_digits(mcc, mnc):
@@ -276,7 +257,7 @@ def _dbi_binary_quote(s):
m = sum_ m = sum_
e = i e = i
if m == 0: # No overhead ? use this ! if m == 0: # No overhead ? use this !
break break;
# Generate output # Generate output
out = [] out = []
@@ -319,7 +300,7 @@ def gen_parameters(opts):
if opts.name is not None: if opts.name is not None:
if len(opts.name) > 16: if len(opts.name) > 16:
raise ValueError('Service Provider Name must max 16 characters!') raise ValueError('Service Provider Name must max 16 characters!');
if opts.msisdn is not None: if opts.msisdn is not None:
msisdn = opts.msisdn msisdn = opts.msisdn
@@ -336,7 +317,7 @@ def gen_parameters(opts):
if opts.iccid is not None: if opts.iccid is not None:
iccid = opts.iccid iccid = opts.iccid
if not _isnum(iccid, 19) and not _isnum(iccid, 20): if not _isnum(iccid, 19) and not _isnum(iccid, 20):
raise ValueError('ICCID must be 19 or 20 digits !') raise ValueError('ICCID must be 19 or 20 digits !');
else: else:
if opts.num is None: if opts.num is None:
@@ -448,15 +429,6 @@ def gen_parameters(opts):
pin_adm = sanitize_pin_adm(opts) pin_adm = sanitize_pin_adm(opts)
# ePDG Selection Information
if opts.epdgSelection:
if len(opts.epdgSelection) < 5 or len(opts.epdgSelection) > 6:
raise ValueError('ePDG Selection Information is not valid')
epdg_mcc = opts.epdgSelection[:3]
epdg_mnc = opts.epdgSelection[3:]
if not epdg_mcc.isdigit() or not epdg_mnc.isdigit():
raise ValueError('PLMN for ePDG Selection must only contain decimal digits')
# Return that # Return that
return { return {
'name' : opts.name, 'name' : opts.name,
@@ -470,12 +442,6 @@ def gen_parameters(opts):
'acc' : acc, 'acc' : acc,
'pin_adm' : pin_adm, 'pin_adm' : pin_adm,
'msisdn' : opts.msisdn, 'msisdn' : opts.msisdn,
'epdgid' : opts.epdgid,
'epdgSelection' : opts.epdgSelection,
'pcscf' : opts.pcscf,
'ims_hdomain': opts.ims_hdomain,
'impi' : opts.impi,
'impu' : opts.impu,
} }
@@ -522,15 +488,15 @@ def _read_params_csv(opts, iccid=None, imsi=None):
if opts.num is not None and opts.read_iccid is False and opts.read_imsi is False: if opts.num is not None and opts.read_iccid is False and opts.read_imsi is False:
if opts.num == i: if opts.num == i:
f.close() f.close()
return row return row;
i += 1 i += 1
if row['iccid'] == iccid: if row['iccid'] == iccid:
f.close() f.close()
return row return row;
if row['imsi'] == imsi: if row['imsi'] == imsi:
f.close() f.close()
return row return row;
f.close() f.close()
return None return None
@@ -677,13 +643,13 @@ def process_card(opts, first, card_handler):
if opts.read_iccid: if opts.read_iccid:
if opts.dry_run: if opts.dry_run:
# Connect transport # Connect transport
card_handler.get(False) card_handler.get(false)
(res,_) = scc.read_binary(['3f00', '2fe2'], length=10) (res,_) = scc.read_binary(['3f00', '2fe2'], length=10)
iccid = dec_iccid(res) iccid = dec_iccid(res)
elif opts.read_imsi: elif opts.read_imsi:
if opts.dry_run: if opts.dry_run:
# Connect transport # Connect transport
card_handler.get(False) card_handler.get(false)
(res,_) = scc.read_binary(EF['IMSI']) (res,_) = scc.read_binary(EF['IMSI'])
imsi = swap_nibbles(res)[3:] imsi = swap_nibbles(res)[3:]
else: else:
@@ -720,8 +686,6 @@ if __name__ == '__main__':
# Init card reader driver # Init card reader driver
sl = init_reader(opts) sl = init_reader(opts)
if sl is None:
exit(1)
# Create command layer # Create command layer
scc = SimCardCommands(transport=sl) scc = SimCardCommands(transport=sl)

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python2
# #
# Utility to display some informations about a SIM card # Utility to display some informations about a SIM card
@@ -28,15 +28,14 @@ import os
import random import random
import re import re
import sys import sys
from pySim.ts_51_011 import EF, DF, EF_SST_map, EF_AD_mode_map from pySim.ts_51_011 import EF, DF, EF_SST_map
from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map
from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map from pySim.ts_31_103 import EF_IST_map
from pySim.commands import SimCardCommands from pySim.commands import SimCardCommands
from pySim.cards import card_detect, Card, UsimCard, IsimCard from pySim.cards import card_detect, Card
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, dec_msisdn from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, dec_msisdn
from pySim.utils import format_xplmn_w_act, dec_spn, dec_st, init_reader, dec_addr_tlv from pySim.utils import format_xplmn_w_act, dec_spn, dec_st, init_reader, dec_epdgid
from pySim.utils import h2s, format_ePDGSelection
def parse_options(): def parse_options():
@@ -82,8 +81,6 @@ if __name__ == '__main__':
# Init card reader driver # Init card reader driver
sl = init_reader(opts) sl = init_reader(opts)
if sl is None:
exit(1)
# Create command layer # Create command layer
scc = SimCardCommands(transport=sl) scc = SimCardCommands(transport=sl)
@@ -228,15 +225,7 @@ if __name__ == '__main__':
# EF.AD # EF.AD
(res, sw) = card.read_binary('AD') (res, sw) = card.read_binary('AD')
if sw == '9000': if sw == '9000':
print("Administrative data: %s" % (res,)) print("AD: %s" % (res,))
if res[:2] in EF_AD_mode_map:
print("\tMS operation mode: %s" % (EF_AD_mode_map[res[:2]],))
else:
print("\tMS operation mode: (unknown 0x%s)" % (res[:2],))
if int(res[4:6], 16) & 0x01:
print("\tCiphering Indicator: enabled")
else:
print("\tCiphering Indicator: disabled")
else: else:
print("AD: Can't read, response code = %s" % (sw,)) print("AD: Can't read, response code = %s" % (sw,))
@@ -252,104 +241,33 @@ 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():
# Select USIM profile
usim_card = UsimCard(scc)
# EF.EHPLMN # EF.EHPLMN
if usim_card.file_exists(EF_USIM_ADF_map['EHPLMN']): if card.file_exists(EF_USIM_ADF_map['EHPLMN']):
(res, sw) = usim_card.read_ehplmn() (res, sw) = card.read_ehplmn()
if sw == '9000': if sw == '9000':
print("EHPLMN:\n%s" % (res)) print("EHPLMN:\n%s" % (res))
else: else:
print("EHPLMN: Can't read, response code = %s" % (sw,)) print("EHPLMN: Can't read, response code = %s" % (sw,))
# EF.UST # EF.UST
try: (res, sw) = card.read_binary(EF_USIM_ADF_map['UST'])
if usim_card.file_exists(EF_USIM_ADF_map['UST']): if sw == '9000':
# res[0] - EF content of UST print("USIM Service Table: %s" % res)
# res[1] - Human readable format of services marked available in UST # Print those which are available
(res, sw) = usim_card.read_ust() print("%s" % dec_st(res, table="usim"))
if sw == '9000': else:
print("USIM Service Table: %s" % res[0]) print("USIM Service Table: Can't read, response code = %s" % (sw,))
print("%s" % res[1])
else:
print("USIM Service Table: Can't read, response code = %s" % (sw,))
except Exception as e:
print("USIM Service Table: Can't read file -- " + str(e))
#EF.ePDGId - Home ePDG Identifier #EF.ePDGId - Home ePDG Identifier
try: try:
if usim_card.file_exists(EF_USIM_ADF_map['ePDGId']): (res, sw) = card.read_binary(EF_USIM_ADF_map['ePDGId'])
(res, sw) = usim_card.read_epdgid() if sw == '9000':
if sw == '9000': content = dec_epdgid(res)
print("ePDGId:\n%s" % (len(res) and res or '\tNot available\n',)) print("ePDGId:\n%s" % (len(content) and content or '\tNot available\n',))
else: else:
print("ePDGId: Can't read, response code = %s" % (sw,)) print("ePDGId: Can't read, response code = %s" % (sw,))
except Exception as e: except Exception as e:
print("ePDGId: Can't read file -- " + str(e)) print("ePDGId: Can't read file -- " + str(e))
#EF.ePDGSelection - ePDG Selection Information
try:
if usim_card.file_exists(EF_USIM_ADF_map['ePDGSelection']):
(res, sw) = usim_card.read_ePDGSelection()
if sw == '9000':
print("ePDGSelection:\n%s" % (res,))
else:
print("ePDGSelection: Can't read, response code = %s" % (sw,))
except Exception as e:
print("ePDGSelection: Can't read file -- " + str(e))
# Select ISIM application by its AID
if '9000' == card.select_adf_by_aid(adf="isim"):
# Select USIM profile
isim_card = IsimCard(scc)
#EF.P-CSCF - P-CSCF Address
try:
if isim_card.file_exists(EF_ISIM_ADF_map['PCSCF']):
res = isim_card.read_pcscf()
print("P-CSCF:\n%s" % (len(res) and res or '\tNot available\n',))
except Exception as e:
print("P-CSCF: Can't read file -- " + str(e))
# EF.DOMAIN - Home Network Domain Name e.g. ims.mncXXX.mccXXX.3gppnetwork.org
try:
if isim_card.file_exists(EF_ISIM_ADF_map['DOMAIN']):
(res, sw) = isim_card.read_domain()
if sw == '9000':
print("Home Network Domain Name: %s" % (len(res) and res or 'Not available',))
else:
print("Home Network Domain Name: Can't read, response code = %s" % (sw,))
except Exception as e:
print("Home Network Domain Name: Can't read file -- " + str(e))
# EF.IMPI - IMS private user identity
try:
if isim_card.file_exists(EF_ISIM_ADF_map['IMPI']):
(res, sw) = isim_card.read_impi()
if sw == '9000':
print("IMS private user identity: %s" % (len(res) and res or 'Not available',))
else:
print("IMS private user identity: Can't read, response code = %s" % (sw,))
except Exception as e:
print("IMS private user identity: Can't read file -- " + str(e))
# EF.IMPU - IMS public user identity
try:
if isim_card.file_exists(EF_ISIM_ADF_map['IMPU']):
res = isim_card.read_impu()
print("IMS public user identity:\n%s" % (len(res) and res or '\tNot available\n',))
except Exception as e:
print("IMS public user identity: Can't read file -- " + str(e))
# EF.UICCIARI - UICC IARI
try:
if isim_card.file_exists(EF_ISIM_ADF_map['UICCIARI']):
res = isim_card.read_iari()
print("UICC IARI:\n%s" % (len(res) and res or '\tNot available\n',))
except Exception as e:
print("UICC IARI: Can't read file -- " + str(e))
# Check whether we have th AID of ISIM, if so select it by its AID # Check whether we have th AID of ISIM, if so select it by its AID
# EF.IST - File Id in ADF ISIM : 6f07 # EF.IST - File Id in ADF ISIM : 6f07
if '9000' == card.select_adf_by_aid(adf="isim"): if '9000' == card.select_adf_by_aid(adf="isim"):

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python2
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
""" pySim: card handler utilities """ pySim: card handler utilities

View File

@@ -25,10 +25,8 @@
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.ts_31_102 import EF_USIM_ADF_map
from pySim.ts_31_103 import EF_ISIM_ADF_map
from pySim.utils import * from pySim.utils import *
from smartcard.util import toBytes from smartcard.util import toBytes
from pytlv.TLV import *
class Card(object): class Card(object):
@@ -206,6 +204,30 @@ class Card(object):
else: else:
return (None, sw) return (None, sw)
# Read the (full) AID for either ISIM or USIM or ISIM application
def read_aid(self, isim = False):
# First (known) halves of the AID
aid_usim = "a0000000871002"
aid_isim = "a0000000871004"
# Select which one to look for
if isim:
aid = aid_isim
else:
aid = aid_usim
# Find out how many records the EF.DIR has, then go through
# all records and try to find the AID we are looking for
aid_record_count = self._scc.record_count(['2F00'])
for i in range(0, aid_record_count):
record = self._scc.read_record(['2F00'], i + 1)
if aid in record[0]:
aid_len = int(record[0][6:8], 16)
return record[0][8:8 + aid_len * 2]
return None
# Fetch all the AIDs present on UICC # Fetch all the AIDs present on UICC
def read_aids(self): def read_aids(self):
try: try:
@@ -266,177 +288,7 @@ class UsimCard(Card):
data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], ehplmn) data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], ehplmn)
return sw return sw
def read_epdgid(self):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
if sw == '9000':
return (dec_addr_tlv(res), sw)
else:
return (None, sw)
def update_epdgid(self, epdgid):
size = self._scc.binary_size(EF_USIM_ADF_map['ePDGId']) * 2
if len(epdgid) > 0:
addr_type = get_addr_type(epdgid)
if addr_type == None:
raise ValueError("Unknown ePDG Id address type or invalid address provided")
epdgid_tlv = rpad(enc_addr_tlv(epdgid, ('%02x' % addr_type)), size)
else:
epdgid_tlv = rpad('ff', size)
data, sw = self._scc.update_binary(
EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
return sw
def read_ePDGSelection(self):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'])
if sw == '9000':
return (format_ePDGSelection(res), sw)
else:
return (None, sw)
def update_ePDGSelection(self, mcc, mnc):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'], length=None, offset=0)
if sw == '9000' and (len(mcc) == 0 or len(mnc) == 0):
# Reset contents
# 80 - Tag value
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['ePDGSelection'], rpad('', len(res)))
elif sw == '9000':
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['ePDGSelection'], enc_ePDGSelection(res, mcc, mnc))
return sw
def read_ust(self):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
if sw == '9000':
# Print those which are available
return ([res, dec_st(res, table="usim")], sw)
else:
return ([None, None], sw)
def update_ust(self, service, bit=1):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
if sw == '9000':
content = enc_st(res, service, bit)
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['UST'], content)
return sw
class IsimCard(Card):
def __init__(self, ssc):
super(IsimCard, self).__init__(ssc)
def read_pcscf(self):
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['PCSCF'])
pcscf_recs = ""
for i in range(0, rec_cnt):
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['PCSCF'], i + 1)
if sw == '9000':
content = dec_addr_tlv(res)
pcscf_recs += "%s" % (len(content) and content or '\tNot available\n')
else:
pcscf_recs += "\tP-CSCF: Can't read, response code = %s\n" % (sw)
return pcscf_recs
def update_pcscf(self, pcscf):
if len(pcscf) > 0:
addr_type = get_addr_type(pcscf)
if addr_type == None:
raise ValueError("Unknown PCSCF address type or invalid address provided")
content = enc_addr_tlv(pcscf, ('%02x' % addr_type))
else:
# Just the tag value
content = '80'
rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['PCSCF'])
pcscf_tlv = rpad(content, rec_size_bytes*2)
data, sw = self._scc.update_record(EF_ISIM_ADF_map['PCSCF'], 1, pcscf_tlv)
return sw
def read_domain(self):
(res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['DOMAIN'])
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
return (content, sw)
else:
return (None, sw)
def update_domain(self, domain=None, mcc=None, mnc=None):
hex_str = ""
if domain:
hex_str = s2h(domain)
elif mcc and mnc:
# MCC and MNC always has 3 digits in domain form
plmn_str = 'mnc' + lpad(mnc, 3, "0") + '.mcc' + lpad(mcc, 3, "0")
hex_str = s2h('ims.' + plmn_str + '.3gppnetwork.org')
# Build TLV
tlv = TLV(['80'])
content = tlv.build({'80': hex_str})
bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['DOMAIN'])
data, sw = self._scc.update_binary(EF_ISIM_ADF_map['DOMAIN'], rpad(content, bin_size_bytes*2))
return sw
def read_impi(self):
(res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IMPI'])
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
return (content, sw)
else:
return (None, sw)
def update_impi(self, impi=None):
hex_str = ""
if impi:
hex_str = s2h(impi)
# Build TLV
tlv = TLV(['80'])
content = tlv.build({'80': hex_str})
bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['IMPI'])
data, sw = self._scc.update_binary(EF_ISIM_ADF_map['IMPI'], rpad(content, bin_size_bytes*2))
return sw
def read_impu(self):
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['IMPU'])
impu_recs = ""
for i in range(0, rec_cnt):
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['IMPU'], i + 1)
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
impu_recs += "\t%s\n" % (len(content) and content or 'Not available')
else:
impu_recs += "IMS public user identity: Can't read, response code = %s\n" % (sw)
return impu_recs
def update_impu(self, impu=None):
hex_str = ""
if impu:
hex_str = s2h(impu)
# Build TLV
tlv = TLV(['80'])
content = tlv.build({'80': hex_str})
rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['IMPU'])
impu_tlv = rpad(content, rec_size_bytes*2)
data, sw = self._scc.update_record(EF_ISIM_ADF_map['IMPU'], 1, impu_tlv)
return sw
def read_iari(self):
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['UICCIARI'])
uiari_recs = ""
for i in range(0, rec_cnt):
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['UICCIARI'], i + 1)
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
uiari_recs += "\t%s\n" % (len(content) and content or 'Not available')
else:
uiari_recs += "UICC IARI: Can't read, response code = %s\n" % (sw)
return uiari_recs
class _MagicSimBase(Card): class _MagicSimBase(Card):
""" """
@@ -481,7 +333,7 @@ class _MagicSimBase(Card):
r = self._scc.select_file(['3f00', '7f4d', f[0]]) r = self._scc.select_file(['3f00', '7f4d', f[0]])
rec_len = int(r[-1][28:30], 16) rec_len = int(r[-1][28:30], 16)
tlen = int(r[-1][4:8],16) tlen = int(r[-1][4:8],16)
rec_cnt = (tlen / rec_len) - 1 rec_cnt = (tlen / rec_len) - 1;
if (rec_cnt < 1) or (rec_len != f[1]): if (rec_cnt < 1) or (rec_len != f[1]):
raise RuntimeError('Bad card type') raise RuntimeError('Bad card type')
@@ -611,7 +463,7 @@ class FakeMagicSim(Card):
r = self._scc.select_file(['3f00', '000c']) r = self._scc.select_file(['3f00', '000c'])
rec_len = int(r[-1][28:30], 16) rec_len = int(r[-1][28:30], 16)
tlen = int(r[-1][4:8],16) tlen = int(r[-1][4:8],16)
rec_cnt = (tlen / rec_len) - 1 rec_cnt = (tlen / rec_len) - 1;
if (rec_cnt < 1) or (rec_len != 0x5a): if (rec_cnt < 1) or (rec_len != 0x5a):
raise RuntimeError('Bad card type') raise RuntimeError('Bad card type')
@@ -772,9 +624,9 @@ class SysmoSIMgr2(Card):
def program(self, p): def program(self, p):
# select MF # select MF
r = self._scc.select_file(['3f00']) r = self._scc.select_file(['3f00'])
# authenticate as SUPER ADM using default key # authenticate as SUPER ADM using default key
self._scc.verify_chv(0x0b, h2b("3838383838383838")) self._scc.verify_chv(0x0b, h2b("3838383838383838"))
@@ -790,7 +642,7 @@ class SysmoSIMgr2(Card):
pdu = 'A0D43A0508' + b2h(pin) pdu = 'A0D43A0508' + b2h(pin)
data, sw = self._scc._tp.send_apdu(pdu) data, sw = self._scc._tp.send_apdu(pdu)
# authenticate as ADM (enough to write file, and can set PINs) # authenticate as ADM (enough to write file, and can set PINs)
self._scc.verify_chv(0x05, pin) self._scc.verify_chv(0x05, pin)
@@ -800,7 +652,7 @@ class SysmoSIMgr2(Card):
# select DF_GSM # select DF_GSM
r = self._scc.select_file(['7f20']) r = self._scc.select_file(['7f20'])
# write EF.IMSI # write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi'])) data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
@@ -822,7 +674,7 @@ class SysmoSIMgr2(Card):
# select DF_TELECOM # select DF_TELECOM
r = self._scc.select_file(['3f00', '7f10']) r = self._scc.select_file(['3f00', '7f10'])
# write EF.SMSP # write EF.SMSP
if p.get('smsp'): if p.get('smsp'):
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80)) data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
@@ -932,7 +784,7 @@ class SysmoUSIMSJS1(UsimCard):
data, sw = self._scc.update_record('6F40', 1, data, force_len=True) data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
class FairwavesSIM(UsimCard): class FairwavesSIM(Card):
""" """
FairwavesSIM FairwavesSIM
@@ -1121,7 +973,7 @@ class OpenCellsSim(Card):
# write EF.IMSI # write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi'])) data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
class WavemobileSim(UsimCard): class WavemobileSim(Card):
""" """
WavemobileSim WavemobileSim
@@ -1212,7 +1064,7 @@ class WavemobileSim(UsimCard):
return None return None
class SysmoISIMSJA2(UsimCard, IsimCard): class SysmoISIMSJA2(UsimCard):
""" """
sysmocom sysmoISIM-SJA2 sysmocom sysmoISIM-SJA2
""" """
@@ -1300,26 +1152,6 @@ class SysmoISIMSJA2(UsimCard, IsimCard):
r = self._scc.select_file(['3f00', '7f10']) r = self._scc.select_file(['3f00', '7f10'])
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True) data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
# EF.MSISDN
# TODO: Alpha Identifier (currently 'ff'O * 20)
# TODO: Capability/Configuration1 Record Identifier
# TODO: Extension1 Record Identifier
if p.get('msisdn') is not None:
msisdn = enc_msisdn(p['msisdn'])
content = 'ff' * 20 + msisdn + 'ff' * 2
r = self._scc.select_file(['3f00', '7f10'])
data, sw = self._scc.update_record('6F40', 1, content, force_len=True)
# EF.ACC
if p.get('acc'):
sw = self.update_acc(p['acc'])
if sw != '9000':
print("Programming ACC failed with code %s"%sw)
# Populate AIDs
self.read_aids()
# update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is # update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
# hard linked to EF-USIM_AUTH_KEY) # hard linked to EF-USIM_AUTH_KEY)
self._scc.select_file(['3f00']) self._scc.select_file(['3f00'])
@@ -1330,55 +1162,20 @@ class SysmoISIMSJA2(UsimCard, IsimCard):
self._scc.update_binary('6f20', p['opc'], 17) self._scc.update_binary('6f20', p['opc'], 17)
# update EF-USIM_AUTH_KEY in ADF.ISIM # update EF-USIM_AUTH_KEY in ADF.ISIM
if '9000' == self.select_adf_by_aid(adf="isim"): self._scc.select_file(['3f00'])
aid = self.read_aid(isim = True)
if (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.P-CSCF in ADF.ISIM self._scc.select_file(['3f00'])
if self.file_exists(EF_ISIM_ADF_map['PCSCF']): aid = self.read_aid()
if p.get('pcscf'): if (aid):
sw = self.update_pcscf(p['pcscf'])
else:
sw = self.update_pcscf("")
if sw != '9000':
print("Programming P-CSCF failed with code %s"%sw)
# update EF.DOMAIN in ADF.ISIM
if self.file_exists(EF_ISIM_ADF_map['DOMAIN']):
if p.get('ims_hdomain'):
sw = self.update_domain(domain=p['ims_hdomain'])
else:
sw = self.update_domain()
if sw != '9000':
print("Programming Home Network Domain Name failed with code %s"%sw)
# update EF.IMPI in ADF.ISIM
# TODO: Validate IMPI input
if self.file_exists(EF_ISIM_ADF_map['IMPI']):
if p.get('impi'):
sw = self.update_impi(p['impi'])
else:
sw = self.update_impi()
if sw != '9000':
print("Programming IMPI failed with code %s"%sw)
# update EF.IMPU in ADF.ISIM
# TODO: Validate IMPU input
# Support multiple IMPU if there is enough space
if self.file_exists(EF_ISIM_ADF_map['IMPU']):
if p.get('impu'):
sw = self.update_impu(p['impu'])
else:
sw = self.update_impu()
if sw != '9000':
print("Programming IMPU failed with code %s"%sw)
if '9000' == self.select_adf_by_aid():
# update EF-USIM_AUTH_KEY in ADF.USIM # update EF-USIM_AUTH_KEY in ADF.USIM
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'):
@@ -1390,49 +1187,6 @@ class SysmoISIMSJA2(UsimCard, IsimCard):
sw = self.update_ehplmn(p['mcc'], p['mnc']) sw = self.update_ehplmn(p['mcc'], p['mnc'])
if sw != '9000': if sw != '9000':
print("Programming EHPLMN failed with code %s"%sw) print("Programming EHPLMN failed with code %s"%sw)
# update EF.ePDGId in ADF.USIM
if self.file_exists(EF_USIM_ADF_map['ePDGId']):
if p.get('epdgid'):
sw = self.update_epdgid(p['epdgid'])
else:
sw = self.update_epdgid("")
if sw != '9000':
print("Programming ePDGId failed with code %s"%sw)
# update EF.ePDGSelection in ADF.USIM
if self.file_exists(EF_USIM_ADF_map['ePDGSelection']):
if p.get('epdgSelection'):
epdg_plmn = p['epdgSelection']
sw = self.update_ePDGSelection(epdg_plmn[:3], epdg_plmn[3:])
else:
sw = self.update_ePDGSelection("", "")
if sw != '9000':
print("Programming ePDGSelection failed with code %s"%sw)
# After successfully programming EF.ePDGId and EF.ePDGSelection,
# Set service 106 and 107 as available in EF.UST
# Disable service 95, 99, 115 if ISIM application is present
if self.file_exists(EF_USIM_ADF_map['UST']):
if p.get('epdgSelection') and p.get('epdgid'):
sw = self.update_ust(106, 1)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(107, 1)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(95, 0)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(99, 0)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(115, 0)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
return return

View File

@@ -26,7 +26,7 @@ from pySim.utils import rpad, b2h
class SimCardCommands(object): class SimCardCommands(object):
def __init__(self, transport): def __init__(self, transport):
self._tp = transport self._tp = transport;
self._cla_byte = "a0" self._cla_byte = "a0"
self.sel_ctrl = "0000" self.sel_ctrl = "0000"

View File

@@ -24,10 +24,10 @@
from smartcard.CardConnection import CardConnection from smartcard.CardConnection import CardConnection
from smartcard.CardRequest import CardRequest from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException, CardConnectionException from smartcard.Exceptions import NoCardException, CardRequestTimeoutException
from smartcard.System import readers from smartcard.System import readers
from pySim.exceptions import NoCardError, ProtocolError from pySim.exceptions import NoCardError
from pySim.transport import LinkBase from pySim.transport import LinkBase
from pySim.utils import h2i, i2h from pySim.utils import h2i, i2h
@@ -35,7 +35,7 @@ from pySim.utils import h2i, i2h
class PcscSimLink(LinkBase): class PcscSimLink(LinkBase):
def __init__(self, reader_number=0): def __init__(self, reader_number=0):
r = readers() r = readers();
self._reader = r[reader_number] self._reader = r[reader_number]
self._con = self._reader.createConnection() self._con = self._reader.createConnection()

View File

@@ -25,7 +25,6 @@ from __future__ import absolute_import
import serial import serial
import time import time
import os.path
from pySim.exceptions import NoCardError, ProtocolError from pySim.exceptions import NoCardError, ProtocolError
from pySim.transport import LinkBase from pySim.transport import LinkBase
@@ -35,8 +34,6 @@ from pySim.utils import h2b, b2h
class SerialSimLink(LinkBase): class SerialSimLink(LinkBase):
def __init__(self, device='/dev/ttyUSB0', baudrate=9600, rst='-rts', debug=False): def __init__(self, device='/dev/ttyUSB0', baudrate=9600, rst='-rts', debug=False):
if not os.path.exists(device):
raise ValueError("device file %s does not exist -- abort" % device)
self._sl = serial.Serial( self._sl = serial.Serial(
port = device, port = device,
parity = serial.PARITY_EVEN, parity = serial.PARITY_EVEN,
@@ -52,8 +49,7 @@ class SerialSimLink(LinkBase):
self._atr = None self._atr = None
def __del__(self): def __del__(self):
if (hasattr(self, "_sl")): self._sl.close()
self._sl.close()
def wait_for_card(self, timeout=None, newcardonly=False): def wait_for_card(self, timeout=None, newcardonly=False):
# Direct try # Direct try
@@ -121,7 +117,7 @@ class SerialSimLink(LinkBase):
rst_meth = rst_meth_map[self._rst_pin[1:]] rst_meth = rst_meth_map[self._rst_pin[1:]]
rst_val = rst_val_map[self._rst_pin[0]] rst_val = rst_val_map[self._rst_pin[0]]
except: except:
raise ValueError('Invalid reset pin %s' % self._rst_pin) raise ValueError('Invalid reset pin %s' % self._rst_pin);
rst_meth(rst_val) rst_meth(rst_val)
time.sleep(0.1) # 100 ms time.sleep(0.1) # 100 ms
@@ -132,7 +128,7 @@ class SerialSimLink(LinkBase):
if not b: if not b:
return 0 return 0
if ord(b) != 0x3b: if ord(b) != 0x3b:
return -1 return -1;
self._dbg_print("TS: 0x%x Direct convention" % ord(b)) self._dbg_print("TS: 0x%x Direct convention" % ord(b))
while ord(b) == 0x3b: while ord(b) == 0x3b:
@@ -226,7 +222,7 @@ class SerialSimLink(LinkBase):
if (to_recv == 2) and (b == '\x60'): # Ignore NIL if we have no RX data (hack ?) if (to_recv == 2) and (b == '\x60'): # Ignore NIL if we have no RX data (hack ?)
continue continue
if not b: if not b:
break break;
data += b data += b
# Split datafield from SW # Split datafield from SW

View File

@@ -135,23 +135,6 @@ EF_UST_map = {
109: 'MCPTT', 109: 'MCPTT',
110: 'ePDG configuration Information for Emergency Service support', 110: 'ePDG configuration Information for Emergency Service support',
111: 'ePDG configuration Information for Emergency Service configured', 111: 'ePDG configuration Information for Emergency Service configured',
112: 'eCall Data over IMS',
113: 'URI support for SMS-PP DOWNLOAD as defined in 3GPP TS 31.111 [12]',
114: 'From Preferred',
115: 'IMS configuration data',
116: 'TV configuration',
117: '3GPP PS Data Off',
118: '3GPP PS Data Off Service List',
119: 'V2X',
120: 'XCAP Configuration Data',
121: 'EARFCN list for MTC/NB-IOT UEs',
122: '5GS Mobility Management Information',
123: '5G Security Parameters',
124: 'Subscription identifier privacy support',
125: 'SUCI calculation by the USIM',
126: 'UAC Access Identities support',
127: 'Expect control plane-based Steering of Roaming information during initial registration in VPLMN',
128: 'Call control on PDU Session by USIM',
} }
LOCI_STATUS_map = { LOCI_STATUS_map = {
@@ -160,7 +143,6 @@ LOCI_STATUS_map = {
2: 'plmn not allowed', 2: 'plmn not allowed',
3: 'locatation area not allowed' 3: 'locatation area not allowed'
} }
EF_USIM_ADF_map = { EF_USIM_ADF_map = {
'LI': '6F05', 'LI': '6F05',
'ARR': '6F06', 'ARR': '6F06',

View File

@@ -42,28 +42,5 @@ EF_IST_map = {
16: 'URI support for SMS-PP DOWNLOAD as defined in 3GPP TS 31.111 [31]', 16: 'URI support for SMS-PP DOWNLOAD as defined in 3GPP TS 31.111 [31]',
17: 'From Preferred', 17: 'From Preferred',
18: 'IMS configuration data', 18: 'IMS configuration data',
19: 'XCAP Configuration Data', 19: 'XCAP Configuration Data'
20: 'WebRTC URI',
}
EF_ISIM_ADF_map = {
'IST': '6F07',
'IMPI': '6F02',
'DOMAIN': '6F03',
'IMPU': '6F04',
'AD': '6FAD',
'ARR': '6F06',
'PCSCF': '6F09',
'GBAP': '6FD5',
'GBANL': '6FD7',
'NAFKCA': '6FDD',
'UICCIARI': '6FE7',
'SMS': '6F3C',
'SMSS': '6F43',
'SMSR': '6F47',
'SMSP': '6F42',
'FromPreferred': '6FF7',
'IMSConfigData': '6FF8',
'XCAPConfigData': '6FFC',
'WebRTCURI': '6FFA'
} }

View File

@@ -313,14 +313,4 @@ EF_SST_map = {
57: 'Multimedia Messaging Service (MMS)', 57: 'Multimedia Messaging Service (MMS)',
58: 'Extension 8', 58: 'Extension 8',
59: 'MMS User Connectivity Parameters', 59: 'MMS User Connectivity Parameters',
} }
# 10.3.18 "EF.AD (Administrative data) "
EF_AD_mode_map = {
'00' : 'normal operation',
'80' : 'type approval operations',
'01' : 'normal operation + specific facilities',
'81' : 'type approval operations + specific facilities',
'02' : 'maintenance (off line)',
'04' : 'cell test operation',
}

View File

@@ -122,8 +122,11 @@ def enc_spn(name, hplmn_disp=False, oplmn_disp=False):
if oplmn_disp: byte1 = byte1|0x02 if oplmn_disp: byte1 = byte1|0x02
return i2h([byte1])+s2h(name) return i2h([byte1])+s2h(name)
def hexstr_to_Nbytearr(s, nbytes): def hexstr_to_fivebytearr(s):
return [s[i:i+(nbytes*2)] for i in range(0, len(s), (nbytes*2)) ] 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):
@@ -137,9 +140,9 @@ def dec_mcc_from_plmn(plmn):
def dec_mnc_from_plmn(plmn): def dec_mnc_from_plmn(plmn):
ia = h2i(plmn) ia = h2i(plmn)
digit1 = (ia[1] & 0xF0) >>4 # 2nd byte, MSB digit1 = ia[2] & 0x0F # 3rd byte, LSB
digit2 = ia[2] & 0x0F # 3rd byte, LSB digit2 = (ia[2] & 0xF0) >> 4 # 3rd byte, MSB
digit3 = (ia[2] & 0xF0) >> 4 # 3nd byte, MSB digit3 = (ia[1] & 0xF0) >> 4 # 2nd byte, MSB
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF: if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
return 0xFFF # 4095 return 0xFFF # 4095
return derive_mnc(digit1, digit2, digit3) return derive_mnc(digit1, digit2, digit3)
@@ -174,7 +177,7 @@ def dec_xplmn_w_act(fivehexbytes):
def format_xplmn_w_act(hexstr): def format_xplmn_w_act(hexstr):
s = "" s = ""
for rec_data in hexstr_to_Nbytearr(hexstr, 5): for rec_data in hexstr_to_fivebytearr(hexstr):
rec_info = dec_xplmn_w_act(rec_data) rec_info = dec_xplmn_w_act(rec_data)
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF: if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
rec_str = "unused" rec_str = "unused"
@@ -223,7 +226,7 @@ def dec_xplmn(threehexbytes):
def format_xplmn(hexstr): def format_xplmn(hexstr):
s = "" s = ""
for rec_data in hexstr_to_Nbytearr(hexstr, 3): for rec_data in hexstr_to_threebytearr(hexstr):
rec_info = dec_xplmn(rec_data) rec_info = dec_xplmn(rec_data)
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF: if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
rec_str = "unused" rec_str = "unused"
@@ -249,7 +252,7 @@ def calculate_luhn(cc):
""" """
Calculate Luhn checksum used in e.g. ICCID and IMEI Calculate Luhn checksum used in e.g. ICCID and IMEI
""" """
num = list(map(int, str(cc))) num = map(int, str(cc))
check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10 check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
return 0 if check_digit == 10 else check_digit return 0 if check_digit == 10 else check_digit
@@ -457,62 +460,19 @@ def TLV_parser(bytelist):
bytelist = bytelist[ L+2 : ] bytelist = bytelist[ L+2 : ]
return ret return ret
def enc_st(st, service, state=1): def dec_epdgid(hexstr):
""" """
Encodes the EF S/U/IST/EST and returns the updated Service Table Decode ePDG Id to get EF.ePDGId or EF.ePDGIdEm.
See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.102 and 4.2.104.
Parameters:
st - Current value of SIM/USIM/ISIM Service Table
service - Service Number to encode as activated/de-activated
state - 1 mean activate, 0 means de-activate
Returns:
s - Modified value of SIM/USIM/ISIM Service Table
Default values:
- state: 1 - Sets the particular Service bit to 1
"""
st_bytes = [st[i:i+2] for i in range(0, len(st), 2) ]
s = ""
# Check whether the requested service is present in each byte
for i in range(0, len(st_bytes)):
# Byte i contains info about Services num (8i+1) to num (8i+8)
if service in range((8*i) + 1, (8*i) + 9):
byte = int(st_bytes[i], 16)
# Services in each byte are in order MSB to LSB
# MSB - Service (8i+8)
# LSB - Service (8i+1)
mod_byte = 0x00
# Copy bit by bit contents of byte to mod_byte with modified bit
# for requested service
for j in range(1, 9):
mod_byte = mod_byte >> 1
if service == (8*i) + j:
mod_byte = state == 1 and mod_byte|0x80 or mod_byte&0x7f
else:
mod_byte = byte&0x01 == 0x01 and mod_byte|0x80 or mod_byte&0x7f
byte = byte >> 1
s += ('%02x' % (mod_byte))
else:
s += st_bytes[i]
return s
def dec_addr_tlv(hexstr):
"""
Decode hex string to get EF.P-CSCF Address or EF.ePDGId or EF.ePDGIdEm.
See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104.
""" """
# Convert from hex str to int bytes list # Convert from hex str to int bytes list
addr_tlv_bytes = h2i(hexstr) epdgid_bytes = h2i(hexstr)
s = "" s = ""
# Get list of tuples containing parsed TLVs # Get list of tuples containing parsed TLVs
tlvs = TLV_parser(addr_tlv_bytes) tlvs = TLV_parser(epdgid_bytes)
for tlv in tlvs: for tlv in tlvs:
# tlv = (T, L, [V]) # tlv = (T, L, [V])
@@ -530,45 +490,29 @@ def dec_addr_tlv(hexstr):
# First byte in the value has the address type # First byte in the value has the address type
addr_type = tlv[2][0] addr_type = tlv[2][0]
# TODO: Support parsing of IPv6 # TODO: Support parsing of IPv4 and IPv6
# Address Type: 0x00 (FQDN), 0x01 (IPv4), 0x02 (IPv6), other (Reserved)
if addr_type == 0x00: #FQDN if addr_type == 0x00: #FQDN
# Skip address tye byte i.e. first byte in value list # Skip address tye byte i.e. first byte in value list
content = tlv[2][1:] content = tlv[2][1:]
s += "\t%s # %s\n" % (i2h(content), i2s(content)) s += "\t%s # %s\n" % (i2h(content), i2s(content))
elif addr_type == 0x01: #IPv4
# Skip address tye byte i.e. first byte in value list
# Skip the unused byte in Octect 4 after address type byte as per 3GPP TS 31.102
ipv4 = tlv[2][2:]
content = '.'.join(str(x) for x in ipv4)
s += "\t%s # %s\n" % (i2h(ipv4), content)
return s return s
def enc_addr_tlv(addr, addr_type='00'): def enc_epdgid(epdg_addr, addr_type='00'):
""" """
Encode address TLV object used in EF.P-CSCF Address, EF.ePDGId and EF.ePDGIdEm. Encode ePDG Id so it can be stored to EF.ePDGId or EF.ePDGIdEm.
See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.8, 4.2.102 and 4.2.104. See 3GPP TS 31.102 version 13.4.0 Release 13, section 4.2.102 and 4.2.104.
Default values: Default values:
- addr_type: 00 - FQDN format of Address - addr_type: 00 - FQDN format of ePDG Address
""" """
s = "" s = ""
# TODO: Encoding of IPv6 address # TODO: Encoding of IPv4 and IPv6 address
if addr_type == '00': #FQDN if addr_type == '00':
hex_str = s2h(addr) hex_str = s2h(epdg_addr)
s += '80' + ('%02x' % ((len(hex_str)//2)+1)) + '00' + hex_str s += '80' + ('%02x' % ((len(hex_str)//2)+1)) + '00' + hex_str
elif addr_type == '01': #IPv4
ipv4_list = addr.split('.')
ipv4_str = ""
for i in ipv4_list:
ipv4_str += ('%02x' % (int(i)))
# Unused bytes shall be set to 'ff'. i.e 4th Octet after Address Type is not used
# IPv4 Address is in octet 5 to octet 8 of the TLV data object
s += '80' + ('%02x' % ((len(ipv4_str)//2)+2)) + '01' + 'ff' + ipv4_str
return s return s
@@ -607,158 +551,21 @@ def init_reader(opts):
""" """
Init card reader driver Init card reader driver
""" """
try: if opts.pcsc_dev is not None:
if opts.pcsc_dev is not None: print("Using PC/SC reader interface")
print("Using PC/SC reader interface") from pySim.transport.pcsc import PcscSimLink
from pySim.transport.pcsc import PcscSimLink sl = PcscSimLink(opts.pcsc_dev)
sl = PcscSimLink(opts.pcsc_dev) elif opts.osmocon_sock is not None:
elif opts.osmocon_sock is not None: print("Using Calypso-based (OsmocomBB) reader interface")
print("Using Calypso-based (OsmocomBB) reader interface") from pySim.transport.calypso import CalypsoSimLink
from pySim.transport.calypso import CalypsoSimLink sl = CalypsoSimLink(sock_path=opts.osmocon_sock)
sl = CalypsoSimLink(sock_path=opts.osmocon_sock) elif opts.modem_dev is not None:
elif opts.modem_dev is not None: print("Using modem for Generic SIM Access (3GPP TS 27.007)")
print("Using modem for Generic SIM Access (3GPP TS 27.007)") from pySim.transport.modem_atcmd import ModemATCommandLink
from pySim.transport.modem_atcmd import ModemATCommandLink sl = ModemATCommandLink(device=opts.modem_dev, baudrate=opts.modem_baud)
sl = ModemATCommandLink(device=opts.modem_dev, baudrate=opts.modem_baud) else: # Serial reader is default
else: # Serial reader is default print("Using serial reader interface")
print("Using serial reader interface") from pySim.transport.serial import SerialSimLink
from pySim.transport.serial import SerialSimLink sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
return sl
except Exception as e:
print("Card reader initialization failed with exception:\n" + str(e))
return None
return sl
def enc_ePDGSelection(hexstr, mcc, mnc, epdg_priority='0001', epdg_fqdn_format='00'):
"""
Encode ePDGSelection so it can be stored at EF.ePDGSelection or EF.ePDGSelectionEm.
See 3GPP TS 31.102 version 15.2.0 Release 15, section 4.2.104 and 4.2.106.
Default values:
- epdg_priority: '0001' - 1st Priority
- epdg_fqdn_format: '00' - Operator Identifier FQDN
"""
plmn1 = enc_plmn(mcc, mnc) + epdg_priority + epdg_fqdn_format
# TODO: Handle encoding of Length field for length more than 127 Bytes
content = '80' + ('%02x' % (len(plmn1)//2)) + plmn1
content = rpad(content, len(hexstr))
return content
def dec_ePDGSelection(sixhexbytes):
"""
Decode ePDGSelection to get EF.ePDGSelection or EF.ePDGSelectionEm.
See 3GPP TS 31.102 version 15.2.0 Release 15, section 4.2.104 and 4.2.106.
"""
res = {'mcc': 0, 'mnc': 0, 'epdg_priority': 0, 'epdg_fqdn_format': ''}
plmn_chars = 6
epdg_priority_chars = 4
epdg_fqdn_format_chars = 2
# first three bytes (six ascii hex chars)
plmn_str = sixhexbytes[:plmn_chars]
# two bytes after first three bytes
epdg_priority_str = sixhexbytes[plmn_chars:plmn_chars + epdg_priority_chars]
# one byte after first five bytes
epdg_fqdn_format_str = sixhexbytes[plmn_chars + epdg_priority_chars:plmn_chars + epdg_priority_chars + epdg_fqdn_format_chars]
res['mcc'] = dec_mcc_from_plmn(plmn_str)
res['mnc'] = dec_mnc_from_plmn(plmn_str)
res['epdg_priority'] = epdg_priority_str
res['epdg_fqdn_format'] = epdg_fqdn_format_str == '00' and 'Operator Identifier FQDN' or 'Location based FQDN'
return res
def format_ePDGSelection(hexstr):
ePDGSelection_info_tag_chars = 2
ePDGSelection_info_tag_str = hexstr[:2]
s = ""
# Minimum length
len_chars = 2
# TODO: Need to determine length properly - definite length support only
# Inconsistency in spec: 3GPP TS 31.102 version 15.2.0 Release 15, 4.2.104
# As per spec, length is 5n, n - number of PLMNs
# But, each PLMN entry is made of PLMN (3 Bytes) + ePDG Priority (2 Bytes) + ePDG FQDN format (1 Byte)
# Totalling to 6 Bytes, maybe length should be 6n
len_str = hexstr[ePDGSelection_info_tag_chars:ePDGSelection_info_tag_chars+len_chars]
# Not programmed scenario
if int(len_str, 16) == 255 or int(ePDGSelection_info_tag_str, 16) == 255:
len_chars = 0
ePDGSelection_info_tag_chars = 0
if len_str[0] == '8':
# The bits 7 to 1 denotes the number of length octets if length > 127
if int(len_str[1]) > 0:
# Update number of length octets
len_chars = len_chars * int(len_str[1])
len_str = hexstr[ePDGSelection_info_tag_chars:len_chars]
content_str = hexstr[ePDGSelection_info_tag_chars+len_chars:]
# Right pad to prevent index out of range - multiple of 6 bytes
content_str = rpad(content_str, len(content_str) + (12 - (len(content_str) % 12)))
for rec_data in hexstr_to_Nbytearr(content_str, 6):
rec_info = dec_ePDGSelection(rec_data)
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
rec_str = "unused"
else:
rec_str = "MCC: %03d MNC: %03d ePDG Priority: %s ePDG FQDN format: %s" % \
(rec_info['mcc'], rec_info['mnc'], rec_info['epdg_priority'], rec_info['epdg_fqdn_format'])
s += "\t%s # %s\n" % (rec_data, rec_str)
return s
def get_addr_type(addr):
"""
Validates the given address and returns it's type (FQDN or IPv4 or IPv6)
Return: 0x00 (FQDN), 0x01 (IPv4), 0x02 (IPv6), None (Bad address argument given)
TODO: Handle IPv6
"""
# Empty address string
if not len(addr):
return None
import sys
# Handle python3 and python2 - unicode
if sys.version_info[0] < 3:
addr_str = unicode(addr)
else:
addr_str = addr
addr_list = addr.split('.')
# Check for IPv4/IPv6
try:
import ipaddress
# Throws ValueError if addr is not correct
ipa = ipaddress.ip_address(addr_str)
if ipa.version == 4:
return 0x01
elif ipa.version == 6:
return 0x02
except Exception as e:
invalid_ipv4 = True
for i in addr_list:
# Invalid IPv4 may qualify for a valid FQDN, so make check here
# e.g. 172.24.15.300
import re
if not re.match('^[0-9_]+$', i):
invalid_ipv4 = False
break
if invalid_ipv4:
return None
fqdn_flag = True
for i in addr_list:
# Only Alpha-numeric characters and hyphen - RFC 1035
import re
if not re.match("^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)?$", i):
fqdn_flag = False
break
# FQDN
if fqdn_flag:
return 0x00
return None

View File

@@ -12,7 +12,7 @@ class DecTestCase(unittest.TestCase):
"ffffff0002", "ffffff0002",
"ffffff0001", "ffffff0001",
] ]
self.assertEqual(utils.hexstr_to_Nbytearr(input_str, 5), expected) self.assertEqual(utils.hexstr_to_fivebytearr(input_str), expected)
def testDecMCCfromPLMN(self): def testDecMCCfromPLMN(self):
self.assertEqual(utils.dec_mcc_from_plmn("92f501"), 295) self.assertEqual(utils.dec_mcc_from_plmn("92f501"), 295)

View File

@@ -42,9 +42,7 @@ HPLMNAcT:
ACC: 0008 ACC: 0008
MSISDN: Not available MSISDN: Not available
Administrative data: 00000002 AD: 00000002
MS operation mode: normal operation
Ciphering Indicator: disabled
SIM Service Table: ff3cc3ff030fff0f000fff03f0c0 SIM Service Table: ff3cc3ff030fff0f000fff03f0c0
Service 1 - CHV1 disable function Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN) Service 2 - Abbreviated Dialling Numbers (ADN)
@@ -116,5 +114,6 @@ USIM Service Table: 01ea1ffc21360480010000
Service 64 - VGCS security Service 64 - VGCS security
Service 65 - VBS security Service 65 - VBS security
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
Done ! Done !

View File

@@ -49,9 +49,7 @@ OPLMNwAcT:
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 6a82. HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 6a82.
ACC: abce ACC: abce
MSISDN: Not available MSISDN: Not available
Administrative data: 00ffff02 AD: 00ffff02
MS operation mode: normal operation
Ciphering Indicator: enabled
SIM Service Table: ff33ff0f3c00ff0f000cf0c0f0030000 SIM Service Table: ff33ff0f3c00ff0f000cf0c0f0030000
Service 1 - CHV1 disable function Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN) Service 2 - Abbreviated Dialling Numbers (ADN)
@@ -132,5 +130,6 @@ USIM Service Table: 9eff1b3c37fe5900000000
Service 53 - Extension 8 Service 53 - Extension 8
Service 55 - MMS User Connectivity Parameters Service 55 - MMS User Connectivity Parameters
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
Done ! Done !

View File

@@ -16,9 +16,7 @@ OPLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404. HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
ACC: ffff ACC: ffff
MSISDN: Not available MSISDN: Not available
Administrative data: 000000 AD: 000000
MS operation mode: normal operation
Ciphering Indicator: disabled
SIM Service Table: ff3fff0f0300f003000c SIM Service Table: ff3fff0f0300f003000c
Service 1 - CHV1 disable function Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN) Service 2 - Abbreviated Dialling Numbers (ADN)

View File

@@ -4,4 +4,4 @@ ICCID=1122334455667788990
KI=AABBCCDDEEFFAABBCCDDEEFFAABBCCDD KI=AABBCCDDEEFFAABBCCDDEEFFAABBCCDD
OPC=12345678901234567890123456789012 OPC=12345678901234567890123456789012
IMSI=001010000000102 IMSI=001010000000102
ADM=11111111 ADM=72273953

View File

@@ -1,7 +1,7 @@
Using PC/SC reader interface Using PC/SC reader interface
Reading ... Reading ...
Autodetected card type: sysmoISIM-SJA2 Autodetected card type: sysmoISIM-SJA2
ICCID: 8988211900000000025 ICCID: 8988211900000000004
IMSI: 001010000000102 IMSI: 001010000000102
GID1: ffffffffffffffffffff GID1: ffffffffffffffffffff
GID2: ffffffffffffffffffff GID2: ffffffffffffffffffff
@@ -52,11 +52,9 @@ HPLMNAcT:
ffffff0000 # unused ffffff0000 # unused
ffffff0000 # unused ffffff0000 # unused
ACC: 0200 ACC: 0001
MSISDN (NPI=1 ToN=3): 6766266 MSISDN (NPI=1 ToN=1): +1234
Administrative data: 00000002 AD: 00000002
MS operation mode: normal operation
Ciphering Indicator: disabled
SIM Service Table: ff33ffff3f003f0f300cf0c3f00000 SIM Service Table: ff33ffff3f003f0f300cf0c3f00000
Service 1 - CHV1 disable function Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN) Service 2 - Abbreviated Dialling Numbers (ADN)
@@ -103,12 +101,12 @@ SIM Service Table: ff33ffff3f003f0f300cf0c3f00000
Service 59 - MMS User Connectivity Parameters Service 59 - MMS User Connectivity Parameters
EHPLMN: EHPLMN:
00f110 # MCC: 001 MNC: 001 00f110 # MCC: 001 MNC: 001
ffffff # unused ffffff # unused
ffffff # unused ffffff # unused
ffffff # unused ffffff # unused
USIM Service Table: beff9f9de73e0408400170330006002e00000000 USIM Service Table: beff9f9de73e0408400170730000002e00000000
Service 2 - Fixed Dialling Numbers (FDN) Service 2 - Fixed Dialling Numbers (FDN)
Service 3 - Extension 2 Service 3 - Extension 2
Service 4 - Service Dialling Numbers (SDN) Service 4 - Service Dialling Numbers (SDN)
@@ -156,54 +154,11 @@ USIM Service Table: beff9f9de73e0408400170330006002e00000000
Service 90 - Operator CSG Lists and corresponding indications Service 90 - Operator CSG Lists and corresponding indications
Service 93 - Communication Control for IMS by USIM Service 93 - Communication Control for IMS by USIM
Service 94 - Extended Terminal Applications Service 94 - Extended Terminal Applications
Service 106 - ePDG configuration Information support Service 95 - Support of UICC access to IMS
Service 107 - ePDG configuration Information configured
Service 122 - 5GS Mobility Management Information
Service 123 - 5G Security Parameters
Service 124 - Subscription identifier privacy support
Service 126 - UAC Access Identities support
ePDGId: ePDGId:
Not available Not available
ePDGSelection:
ffffffffffff # unused
ffffffffffff # unused
ffffffffffff # unused
ffffffffffff # unused
P-CSCF:
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Home Network Domain Name: Not available
IMS private user identity: Not available
IMS public user identity:
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Not available
UICC IARI:
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Not available
ISIM Service Table: 190200 ISIM Service Table: 190200
Service 1 - P-CSCF address Service 1 - P-CSCF address
Service 4 - GBA-based Local Key Establishment Mechanism Service 4 - GBA-based Local Key Establishment Mechanism

View File

@@ -54,9 +54,7 @@ HPLMNAcT:
ACC: 0008 ACC: 0008
MSISDN (NPI=1 ToN=1): +77776336143 MSISDN (NPI=1 ToN=1): +77776336143
Administrative data: 00000002 AD: 00000002
MS operation mode: normal operation
Ciphering Indicator: disabled
SIM Service Table: ff3fffff3f003f1ff00c00c0f00000 SIM Service Table: ff3fffff3f003f1ff00c00c0f00000
Service 1 - CHV1 disable function Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN) Service 2 - Abbreviated Dialling Numbers (ADN)
@@ -140,5 +138,6 @@ USIM Service Table: 9e6b1dfc67f6580000
Service 53 - Extension 8 Service 53 - Extension 8
Service 55 - MMS User Connectivity Parameters Service 55 - MMS User Connectivity Parameters
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
Done ! Done !

View File

@@ -16,9 +16,7 @@ OPLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404. HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
ACC: 0008 ACC: 0008
MSISDN: Not available MSISDN: Not available
Administrative data: 000000 AD: 000000
MS operation mode: normal operation
Ciphering Indicator: disabled
SIM Service Table: ff3fff0f0f0000030000 SIM Service Table: ff3fff0f0f0000030000
Service 1 - CHV1 disable function Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN) Service 2 - Abbreviated Dialling Numbers (ADN)

13
script_format.py Normal file
View File

@@ -0,0 +1,13 @@
class ScriptFormat():
def parse_process(self, text, stmt_cb, stmt_cb_kwargs={}):
p = self.parse_xform(text)
#print(p.pretty())
for stmt in p.children:
stmt_cb(stmt, **stmt_cb_kwargs)
def parse_process_file(self, fname, stmt_cb, stmt_cb_kwargs={}):
f = open(fname, "r")
text = f.read()
return self.parse_process(text, stmt_cb, stmt_cb_kwargs)