2 Commits

Author SHA1 Message Date
Daniel Willmann
1d96d22c11 Add an option to read the iccid and batch-program the new card data
This can be used to reprogram everything including IMSI on the card:

while true; do
 ./pySim-prog.py -p 0 -t sysmoUSIM-SJS1 --source=csv --read-csv=cards.csv --read-iccid &&
   paplay complete.oga
 sleep 2
done

Change-Id: Ib343a29141b5255f67a59ab76959b51e162b7916
2019-08-28 23:22:28 +02:00
Daniel Willmann
1d00c19d14 pySim-prog: Use CSV format with headers
This way we can have optional fields like adm1 in the file
Also require iccid as identifier for the SIM card

Change-Id: I0d317ea51d0cf582b82157eec6cdec074001a236
2019-08-28 23:21:56 +02:00
35 changed files with 409 additions and 2870 deletions

View File

@@ -101,7 +101,7 @@ sc = SimCardCommands(sl)
sl.wait_for_card()
# Print IMSI
print(sc.read_binary(['3f00', '7f20', '6f07']))
print sc.read_binary(['3f00', '7f20', '6f07'])
# Run A3/A8
print(sc.run_gsm('00112233445566778899aabbccddeeff'))
print sc.run_gsm('00112233445566778899aabbccddeeff')

View File

@@ -12,7 +12,6 @@ fi
virtualenv -p python2 venv --system-site-packages
. venv/bin/activate
pip install pytlv
pip install pyyaml
cd pysim-testdata
../tests/pysim-test.sh

View File

@@ -1,16 +0,0 @@
This file aims to describe the format of the CSV file pySim uses.
The first line contains the fieldnames which will be used by pySim. This
avoids having a specific order.
The field names are the following:
iccid: ICCID of the card. Used to identify the cards (with --read-iccid)
imsi: IMSI of the card
mcc: Mobile Country Code (optional)
mnc: Mobile Network Code (optional)
smsp: MSISDN of the SMSC (optional)
ki: Ki
opc: OPc
acc: Access class of the SIM (optional)
pin_adm: Admin PIN of the SIM. Needed to reprogram various files

View File

@@ -1,141 +0,0 @@
#!/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})

View File

@@ -1,55 +0,0 @@
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

View File

@@ -1,74 +0,0 @@
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

View File

@@ -1,84 +0,0 @@
#!/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

@@ -30,7 +30,6 @@ import os
import random
import re
import sys
import traceback
try:
import json
@@ -39,11 +38,9 @@ except ImportError:
import simplejson as json
from pySim.commands import SimCardCommands
from pySim.cards import _cards_classes, card_detect
from pySim.utils import h2b, swap_nibbles, rpad, derive_milenage_opc, calculate_luhn, dec_iccid, init_reader
from pySim.cards import _cards_classes
from pySim.utils import h2b, swap_nibbles, rpad, derive_milenage_opc, calculate_luhn, dec_iccid
from pySim.ts_51_011 import EF
from pySim.card_handler import *
from pySim.utils import *
def parse_options():
@@ -61,14 +58,6 @@ def parse_options():
help="Which PC/SC reader number for SIM access",
default=None,
)
parser.add_option("--modem-device", dest="modem_dev", metavar="DEV",
help="Serial port of modem for Generic SIM Access (3GPP TS 27.007)",
default=None,
)
parser.add_option("--modem-baud", dest="modem_baud", type="int", metavar="BAUD",
help="Baudrate used for modem's port [default: %default]",
default=115200,
)
parser.add_option("--osmocon", dest="osmocon_sock", metavar="PATH",
help="Socket path for Calypso (e.g. Motorola C1XX) based reader (via OsmocomBB)",
default=None,
@@ -84,9 +73,6 @@ def parse_options():
parser.add_option("-a", "--pin-adm", dest="pin_adm",
help="ADM PIN used for provisioning (overwrites default)",
)
parser.add_option("-A", "--pin-adm-hex", dest="pin_adm_hex",
help="ADM PIN used for provisioning, as hex string (16 characters long",
)
parser.add_option("-e", "--erase", dest="erase", action='store_true',
help="Erase beforehand [default: %default]",
default=False,
@@ -106,18 +92,13 @@ def parse_options():
help="Country code [default: %default]",
default=1,
)
parser.add_option("-x", "--mcc", dest="mcc", type="string",
parser.add_option("-x", "--mcc", dest="mcc", type="int",
help="Mobile Country Code [default: %default]",
default="901",
default=901,
)
parser.add_option("-y", "--mnc", dest="mnc", type="string",
parser.add_option("-y", "--mnc", dest="mnc", type="int",
help="Mobile Network Code [default: %default]",
default="55",
)
parser.add_option("--mnclen", dest="mnclen", type="choice",
help="Length of Mobile Network Code [default: %default]",
default=2,
choices=[2, 3],
default=55,
)
parser.add_option("-m", "--smsc", dest="smsc",
help="SMSC number (Start with + for international no.) [default: '00 + country code + 5555']",
@@ -132,9 +113,6 @@ def parse_options():
parser.add_option("-i", "--imsi", dest="imsi",
help="International Mobile Subscriber Identity",
)
parser.add_option("--msisdn", dest="msisdn",
help="Mobile Subscriber Integrated Services Digital Number",
)
parser.add_option("-k", "--ki", dest="ki",
help="Ki (default is to randomize)",
)
@@ -146,7 +124,7 @@ def parse_options():
)
parser.add_option("--acc", dest="acc",
help="Set ACC bits (Access Control Code). not all card types are supported",
)
)
parser.add_option("--read-imsi", dest="read_imsi", action="store_true",
help="Read the IMSI from the CARD", default=False
)
@@ -181,18 +159,16 @@ def parse_options():
parser.add_option("--dry-run", dest="dry_run",
help="Perform a 'dry run', don't actually program the card",
default=False, action="store_true")
parser.add_option("--card_handler", dest="card_handler", metavar="FILE",
help="Use automatic card handling machine")
(options, args) = parser.parse_args()
if options.type == 'list':
for kls in _cards_classes:
print(kls.name)
print kls.name
sys.exit(0)
if options.probe:
return options
if options.probe:
return options
if options.source == 'csv':
if (options.imsi is None) and (options.batch_mode is False) and (options.read_imsi is False) and (options.read_iccid is False):
@@ -227,7 +203,7 @@ def _digits(secret, usage, len, num):
return d[0:len]
def _mcc_mnc_digits(mcc, mnc):
return '%s%s' % (mcc, mnc)
return ('%03d%03d' if mnc > 100 else '%03d%02d') % (mcc, mnc)
def _cc_digits(cc):
return ('%03d' if cc > 100 else '%02d') % cc
@@ -280,17 +256,8 @@ def gen_parameters(opts):
mcc = opts.mcc
mnc = opts.mnc
if not mcc.isdigit() or not mnc.isdigit():
raise ValueError('mcc & mnc must only contain decimal digits')
if len(mcc) < 1 or len(mcc) > 3:
raise ValueError('mcc must be between 1 .. 3 digits')
if len(mnc) < 1 or len(mnc) > 3:
raise ValueError('mnc must be between 1 .. 3 digits')
# MCC always has 3 digits
mcc = lpad(mcc, 3, "0")
# MNC must be at least 2 digits
mnc = lpad(mnc, 2, "0")
if not ((0 < mcc < 999) and (0 < mnc < 999)):
raise ValueError('mcc & mnc must be between 0 and 999')
# Digitize country code (2 or 3 digits)
cc_digits = _cc_digits(opts.country)
@@ -298,21 +265,6 @@ def gen_parameters(opts):
# Digitize MCC/MNC (5 or 6 digits)
plmn_digits = _mcc_mnc_digits(mcc, mnc)
if opts.name is not None:
if len(opts.name) > 16:
raise ValueError('Service Provider Name must max 16 characters!');
if opts.msisdn is not None:
msisdn = opts.msisdn
if msisdn[0] == '+':
msisdn = msisdn[1:]
if not msisdn.isdigit():
raise ValueError('MSISDN must be digits only! '
'Start with \'+\' for international numbers.')
if len(msisdn) > 10 * 2:
# TODO: Support MSISDN of length > 20 (10 Bytes)
raise ValueError('MSISDNs longer than 20 digits are not (yet) supported.')
# ICCID (19 digits, E.118), though some phase1 vendors use 20 :(
if opts.iccid is not None:
iccid = opts.iccid
@@ -326,7 +278,7 @@ def gen_parameters(opts):
iccid = (
'89' + # Common prefix (telecom)
cc_digits + # Country Code on 2/3 digits
plmn_digits # MCC/MNC on 5/6 digits
plmn_digits # MCC/MNC on 5/6 digits
)
ml = 18 - len(iccid)
@@ -427,7 +379,17 @@ def gen_parameters(opts):
else:
opc = ''.join(['%02x' % random.randrange(0,256) for i in range(16)])
pin_adm = sanitize_pin_adm(opts)
if opts.pin_adm is not None:
if len(opts.pin_adm) <= 8:
pin_adm = ''.join(['%02x'%(ord(x)) for x in opts.pin_adm])
pin_adm = rpad(pin_adm, 16)
elif len(opts.pin_adm) == 16:
pin_adm = opts.pin_adm
else:
raise ValueError("PIN-ADM needs to be <=8 digits (ascii) or exactly 16 digits (raw hex)")
else:
pin_adm = None
# Return that
return {
@@ -440,27 +402,23 @@ def gen_parameters(opts):
'ki' : ki,
'opc' : opc,
'acc' : acc,
'pin_adm' : pin_adm,
'msisdn' : opts.msisdn,
'adm1' : pin_adm,
}
def print_parameters(params):
s = ["Generated card parameters :"]
if 'name' in params:
s.append(" > Name : %(name)s")
if 'smsp' in params:
s.append(" > SMSP : %(smsp)s")
s.append(" > ICCID : %(iccid)s")
s.append(" > MCC/MNC : %(mcc)s/%(mnc)s")
s.append(" > IMSI : %(imsi)s")
s.append(" > Ki : %(ki)s")
s.append(" > OPC : %(opc)s")
if 'acc' in params:
s.append(" > ACC : %(acc)s")
s.append(" > ADM1(hex): %(pin_adm)s")
print("\n".join(s) % params)
print """Generated card parameters :
> Name : %(name)s
> SMSP : %(smsp)s
> ICCID : %(iccid)s
> MCC/MNC : %(mcc)d/%(mnc)d
> IMSI : %(imsi)s
> Ki : %(ki)s
> OPC : %(opc)s
> ACC : %(acc)s
> ADM1 : %(adm1)s
""" % params
def write_params_csv(opts, params):
@@ -477,13 +435,9 @@ def _read_params_csv(opts, iccid=None, imsi=None):
import csv
f = open(opts.read_csv, 'r')
cr = csv.DictReader(f)
# Lower-case fieldnames
cr.fieldnames = [ field.lower() for field in cr.fieldnames ]
i = 0
if not 'iccid' in cr.fieldnames:
raise Exception("CSV file in wrong format!")
if not 'iccid' in cr.fieldnames:
raise Exception("CSV file in wrong format!")
for row in cr:
if opts.num is not None and opts.read_iccid is False and opts.read_imsi is False:
if opts.num == i:
@@ -504,33 +458,8 @@ def _read_params_csv(opts, iccid=None, imsi=None):
def read_params_csv(opts, imsi=None, iccid=None):
row = _read_params_csv(opts, iccid=iccid, imsi=imsi)
if row is not None:
row['mcc'] = row.get('mcc', mcc_from_imsi(row.get('imsi')))
row['mnc'] = row.get('mnc', mnc_from_imsi(row.get('imsi')))
pin_adm = None
# We need to escape the pin_adm we get from the csv
if 'pin_adm' in row:
pin_adm = ''.join(['%02x'%(ord(x)) for x in row['pin_adm']])
# Stay compatible to the odoo csv format
elif 'adm1' in row:
pin_adm = ''.join(['%02x'%(ord(x)) for x in row['adm1']])
if pin_adm:
row['pin_adm'] = rpad(pin_adm, 16)
# If the CSV-File defines a pin_adm_hex field use this field to
# generate pin_adm from that.
pin_adm_hex = row.get('pin_adm_hex')
if pin_adm_hex:
if len(pin_adm_hex) == 16:
row['pin_adm'] = pin_adm_hex
# Ensure that it's hex-encoded
try:
try_encode = h2b(pin_adm)
except ValueError:
raise ValueError("pin_adm_hex needs to be hex encoded using this option")
else:
raise ValueError("pin_adm_hex needs to be exactly 16 digits (hex encoded)")
row['mcc'] = int(row['mcc'])
row['mnc'] = int(row['mnc'])
return row
@@ -580,7 +509,7 @@ def init_batch(opts):
for k in BATCH_INCOMPATIBLE:
if getattr(opts, k):
print("Incompatible option with batch_state: %s" % (k,))
print "Incompatible option with batch_state: %s" % (k,)
sys.exit(-1)
# Don't load state if there is none ...
@@ -588,7 +517,7 @@ def init_batch(opts):
return
if not os.path.isfile(opts.batch_state):
print("No state file yet")
print "No state file yet"
return
# Get stored data
@@ -611,72 +540,34 @@ def save_batch(opts):
fh.close()
def process_card(opts, first, card_handler):
def card_detect(opts, scc):
if opts.dry_run is False:
# Connect transport
card_handler.get(first)
# Detect type if needed
card = None
ctypes = dict([(kls.name, kls) for kls in _cards_classes])
if opts.type in ("auto", "auto_once"):
for kls in _cards_classes:
card = kls.autodetect(scc)
if card:
print "Autodetected card type: %s" % card.name
card.reset()
break
if opts.dry_run is False:
# Get card
card = card_detect(opts.type, scc)
if card is None:
print("No card detected!")
return -1
print "Autodetection failed"
return
# Probe only
if opts.probe:
return 0
if opts.type == "auto_once":
opts.type = card.name
# Erase if requested
if opts.erase:
print("Formatting ...")
card.erase()
card.reset()
elif opts.type in ctypes:
card = ctypes[opts.type](scc)
# Generate parameters
if opts.source == 'cmdline':
cp = gen_parameters(opts)
elif opts.source == 'csv':
imsi = None
iccid = None
if opts.read_iccid:
if opts.dry_run:
# Connect transport
card_handler.get(false)
(res,_) = scc.read_binary(['3f00', '2fe2'], length=10)
iccid = dec_iccid(res)
elif opts.read_imsi:
if opts.dry_run:
# Connect transport
card_handler.get(false)
(res,_) = scc.read_binary(EF['IMSI'])
imsi = swap_nibbles(res)[3:]
else:
imsi = opts.imsi
cp = read_params_csv(opts, imsi=imsi, iccid=iccid)
if cp is None:
print("Error reading parameters from CSV file!\n")
return 2
print_parameters(cp)
if opts.dry_run is False:
# Program the card
print("Programming ...")
card.program(cp)
else:
print("Dry Run: NOT PROGRAMMING!")
raise ValueError("Unknown card type: %s" % opts.type)
# Write parameters permanently
write_parameters(opts, cp)
# Batch mode state update and save
if opts.num is not None:
opts.num += 1
save_batch(opts)
card_handler.done()
return 0
return card
if __name__ == '__main__':
@@ -685,56 +576,110 @@ if __name__ == '__main__':
opts = parse_options()
# Init card reader driver
sl = init_reader(opts)
if opts.pcsc_dev is not None:
print("Using PC/SC reader (dev=%d) interface"
% opts.pcsc_dev)
from pySim.transport.pcsc import PcscSimLink
sl = PcscSimLink(opts.pcsc_dev)
elif opts.osmocon_sock is not None:
print("Using Calypso-based (OsmocomBB, sock=%s) reader interface"
% opts.osmocon_sock)
from pySim.transport.calypso import CalypsoSimLink
sl = CalypsoSimLink(sock_path=opts.osmocon_sock)
else: # Serial reader is default
print("Using serial reader (port=%s, baudrate=%d) interface"
% (opts.device, opts.baudrate))
from pySim.transport.serial import SerialSimLink
sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
# Create command layer
scc = SimCardCommands(transport=sl)
# If we use a CSV file as data input, check if the CSV file exists.
if opts.source == 'csv':
print("Using CSV file as data input: " + str(opts.read_csv))
if not os.path.isfile(opts.read_csv):
print("CSV file not found!")
sys.exit(1)
# Batch mode init
init_batch(opts)
if opts.card_handler:
card_handler = card_handler_auto(sl, opts.card_handler)
else:
card_handler = card_handler(sl)
# Iterate
done = False
first = True
card = None
while 1:
try:
rc = process_card(opts, first, card_handler)
except (KeyboardInterrupt):
print("")
print("Terminated by user!")
sys.exit(0)
except (SystemExit):
raise
except:
print("")
print("Card programming failed with an execption:")
print("---------------------8<---------------------")
traceback.print_exc()
print("---------------------8<---------------------")
print("")
rc = -1
while not done:
# Something did not work as well as expected, however, lets
# make sure the card is pulled from the reader.
if rc != 0:
card_handler.error()
# If we are not in batch mode we are done in any case, so lets
# exit here.
if not opts.batch_mode:
sys.exit(rc)
if opts.dry_run is False:
# Connect transport
print "Insert card now (or CTRL-C to cancel)"
sl.wait_for_card(newcardonly=not first)
# Not the first anymore !
first = False
if opts.dry_run is False:
# Get card
card = card_detect(opts, scc)
if card is None:
if opts.batch_mode:
first = False
continue
else:
sys.exit(-1)
# Probe only
if opts.probe:
break;
# Erase if requested
if opts.erase:
print "Formatting ..."
card.erase()
card.reset()
# Generate parameters
if opts.source == 'cmdline':
cp = gen_parameters(opts)
elif opts.source == 'csv':
imsi = None
iccid = None
if opts.read_iccid:
if opts.dry_run:
# Connect transport
print "Insert card now (or CTRL-C to cancel)"
sl.wait_for_card(newcardonly=not first)
(res,_) = scc.read_binary(['3f00', '2fe2'], length=10)
iccid = dec_iccid(res)
print iccid
elif opts.read_imsi:
if opts.dry_run:
# Connect transport
print "Insert card now (or CTRL-C to cancel)"
sl.wait_for_card(newcardonly=not first)
(res,_) = scc.read_binary(EF['IMSI'])
imsi = swap_nibbles(res)[3:]
else:
imsi = opts.imsi
cp = read_params_csv(opts, imsi=imsi, iccid=iccid)
if cp is None:
print "Error reading parameters\n"
sys.exit(2)
print_parameters(cp)
if opts.dry_run is False:
# Program the card
print "Programming ..."
if opts.dry_run is not True:
card.program(cp)
else:
print "Dry Run: NOT PROGRAMMING!"
# Write parameters permanently
write_parameters(opts, cp)
# Batch mode state update and save
if opts.num is not None:
opts.num += 1
save_batch(opts)
# Done for this card and maybe for everything ?
print "Done !\n"
if not opts.batch_mode:
done = True

View File

@@ -28,14 +28,17 @@ import os
import random
import re
import sys
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_103 import EF_IST_map
from pySim.ts_51_011 import EF, DF
try:
import json
except ImportError:
# Python < 2.5
import simplejson as json
from pySim.commands import SimCardCommands
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 format_xplmn_w_act, dec_spn, dec_st, init_reader, dec_epdgid
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, format_xplmn_w_act
def parse_options():
@@ -53,14 +56,6 @@ def parse_options():
help="Which PC/SC reader number for SIM access",
default=None,
)
parser.add_option("--modem-device", dest="modem_dev", metavar="DEV",
help="Serial port of modem for Generic SIM Access (3GPP TS 27.007)",
default=None,
)
parser.add_option("--modem-baud", dest="modem_baud", type="int", metavar="BAUD",
help="Baudrate used for modem's port [default: %default]",
default=115200,
)
parser.add_option("--osmocon", dest="osmocon_sock", metavar="PATH",
help="Socket path for Calypso (e.g. Motorola C1XX) based reader (via OsmocomBB)",
default=None,
@@ -80,7 +75,21 @@ if __name__ == '__main__':
opts = parse_options()
# Init card reader driver
sl = init_reader(opts)
if opts.pcsc_dev is not None:
print("Using PC/SC reader (dev=%d) interface"
% opts.pcsc_dev)
from pySim.transport.pcsc import PcscSimLink
sl = PcscSimLink(opts.pcsc_dev)
elif opts.osmocon_sock is not None:
print("Using Calypso-based (OsmocomBB, sock=%s) reader interface"
% opts.osmocon_sock)
from pySim.transport.calypso import CalypsoSimLink
sl = CalypsoSimLink(sock_path=opts.osmocon_sock)
else: # Serial reader is default
print("Using serial reader (port=%s, baudrate=%d) interface"
% (opts.device, opts.baudrate))
from pySim.transport.serial import SerialSimLink
sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
# Create command layer
scc = SimCardCommands(transport=sl)
@@ -88,121 +97,72 @@ if __name__ == '__main__':
# Wait for SIM card
sl.wait_for_card()
# Assuming UICC SIM
scc.cla_byte = "00"
scc.sel_ctrl = "0004"
# Testing for Classic SIM or UICC
(res, sw) = sl.send_apdu(scc.cla_byte + "a4" + scc.sel_ctrl + "02" + "3f00")
if sw == '6e00':
# Just a Classic SIM
scc.cla_byte = "a0"
scc.sel_ctrl = "0000"
# Program the card
print("Reading ...")
# Initialize Card object by auto detecting the card
card = card_detect("auto", scc) or Card(scc)
# Read all AIDs on the UICC
card.read_aids()
# EF.ICCID
(res, sw) = card.read_iccid()
(res, sw) = scc.read_binary(EF['ICCID'])
if sw == '9000':
print("ICCID: %s" % (res,))
print("ICCID: %s" % (dec_iccid(res),))
else:
print("ICCID: Can't read, response code = %s" % (sw,))
# EF.IMSI
(res, sw) = card.read_imsi()
(res, sw) = scc.read_binary(['3f00', '7f20', '6f07'])
if sw == '9000':
print("IMSI: %s" % (res,))
print("IMSI: %s" % (dec_imsi(res),))
else:
print("IMSI: Can't read, response code = %s" % (sw,))
# EF.GID1
try:
(res, sw) = card.read_gid1()
if sw == '9000':
print("GID1: %s" % (res,))
else:
print("GID1: Can't read, response code = %s" % (sw,))
except Exception as e:
print("GID1: Can't read file -- %s" % (str(e),))
# EF.GID2
try:
(res, sw) = card.read_binary('GID2')
if sw == '9000':
print("GID2: %s" % (res,))
else:
print("GID2: Can't read, response code = %s" % (sw,))
except Exception as e:
print("GID2: Can't read file -- %s" % (str(e),))
# EF.SMSP
(res, sw) = card.read_record('SMSP', 1)
(res, sw) = scc.read_record(['3f00', '7f10', '6f42'], 1)
if sw == '9000':
print("SMSP: %s" % (res,))
else:
print("SMSP: Can't read, response code = %s" % (sw,))
# EF.SPN
try:
(res, sw) = card.read_spn()
if sw == '9000':
print("SPN: %s" % (res[0] or "Not available"))
print("Display HPLMN: %s" % (res[1],))
print("Display OPLMN: %s" % (res[2],))
else:
print("SPN: Can't read, response code = %s" % (sw,))
except Exception as e:
print("SPN: Can't read file -- %s" % (str(e),))
# EF.PLMNsel
try:
(res, sw) = card.read_binary('PLMNsel')
if sw == '9000':
print("PLMNsel: %s" % (res))
else:
print("PLMNsel: Can't read, response code = %s" % (sw,))
(res, sw) = scc.read_binary(EF['PLMNsel'])
if sw == '9000':
print("PLMNsel: %s" % (res))
else:
print("PLMNsel: Can't read, response code = %s" % (sw,))
except Exception as e:
print("PLMNsel: Can't read file -- " + str(e))
print "HPLMNAcT: Can't read file -- " + str(e)
# EF.PLMNwAcT
try:
(res, sw) = card.read_plmn_act()
if sw == '9000':
print("PLMNwAcT:\n%s" % (res))
else:
print("PLMNwAcT: Can't read, response code = %s" % (sw,))
try:
(res, sw) = scc.read_binary(EF['PLMNwAcT'])
if sw == '9000':
print("PLMNwAcT:\n%s" % (format_xplmn_w_act(res)))
else:
print("PLMNwAcT: Can't read, response code = %s" % (sw,))
except Exception as e:
print("PLMNwAcT: Can't read file -- " + str(e))
print "PLMNwAcT: Can't read file -- " + str(e)
# EF.OPLMNwAcT
try:
(res, sw) = card.read_oplmn_act()
if sw == '9000':
print("OPLMNwAcT:\n%s" % (res))
else:
print("OPLMNwAcT: Can't read, response code = %s" % (sw,))
try:
(res, sw) = scc.read_binary(EF['OPLMNwAcT'])
if sw == '9000':
print("OPLMNwAcT:\n%s" % (format_xplmn_w_act(res)))
else:
print("OPLMNwAcT: Can't read, response code = %s" % (sw,))
except Exception as e:
print("OPLMNwAcT: Can't read file -- " + str(e))
print "OPLMNwAcT: Can't read file -- " + str(e)
# EF.HPLMNAcT
try:
(res, sw) = card.read_hplmn_act()
if sw == '9000':
print("HPLMNAcT:\n%s" % (res))
else:
print("HPLMNAcT: Can't read, response code = %s" % (sw,))
try:
(res, sw) = scc.read_binary(EF['HPLMNAcT'])
if sw == '9000':
print("HPLMNAcT:\n%s" % (format_xplmn_w_act(res)))
else:
print("HPLMNAcT: Can't read, response code = %s" % (sw,))
except Exception as e:
print("HPLMNAcT: Can't read file -- " + str(e))
print "HPLMNAcT: Can't read file -- " + str(e)
# EF.ACC
(res, sw) = card.read_binary('ACC')
(res, sw) = scc.read_binary(['3f00', '7f20', '6f78'])
if sw == '9000':
print("ACC: %s" % (res,))
else:
@@ -210,75 +170,24 @@ if __name__ == '__main__':
# EF.MSISDN
try:
(res, sw) = card.read_msisdn()
# print(scc.record_size(['3f00', '7f10', '6f40']))
(res, sw) = scc.read_record(['3f00', '7f10', '6f40'], 1)
if sw == '9000':
# (npi, ton, msisdn) = res
if res is not None:
print("MSISDN (NPI=%d ToN=%d): %s" % res)
if res[1] != 'f':
print("MSISDN: %s" % (res,))
else:
print("MSISDN: Not available")
else:
print("MSISDN: Can't read, response code = %s" % (sw,))
except Exception as e:
print("MSISDN: Can't read file -- " + str(e))
print "MSISDN: Can't read file -- " + str(e)
# EF.AD
(res, sw) = card.read_binary('AD')
(res, sw) = scc.read_binary(['3f00', '7f20', '6fad'])
if sw == '9000':
print("AD: %s" % (res,))
else:
print("AD: Can't read, response code = %s" % (sw,))
# EF.SST
(res, sw) = card.read_binary('SST')
if sw == '9000':
print("SIM Service Table: %s" % res)
# Print those which are available
print("%s" % dec_st(res))
else:
print("SIM Service Table: Can't read, response code = %s" % (sw,))
# Check whether we have th AID of USIM, if so select it by its AID
# EF.UST - File Id in ADF USIM : 6f38
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
(res, sw) = card.read_binary(EF_USIM_ADF_map['UST'])
if sw == '9000':
print("USIM Service Table: %s" % res)
# Print those which are available
print("%s" % dec_st(res, table="usim"))
else:
print("USIM Service Table: Can't read, response code = %s" % (sw,))
#EF.ePDGId - Home ePDG Identifier
try:
(res, sw) = card.read_binary(EF_USIM_ADF_map['ePDGId'])
if sw == '9000':
content = dec_epdgid(res)
print("ePDGId:\n%s" % (len(content) and content or '\tNot available\n',))
else:
print("ePDGId: Can't read, response code = %s" % (sw,))
except Exception as e:
print("ePDGId: Can't read file -- " + str(e))
# Check whether we have th AID of ISIM, if so select it by its AID
# EF.IST - File Id in ADF ISIM : 6f07
if '9000' == card.select_adf_by_aid(adf="isim"):
# EF.IST
(res, sw) = card.read_binary('6f07')
if sw == '9000':
print("ISIM Service Table: %s" % res)
# Print those which are available
print("%s" % dec_st(res, table="isim"))
else:
print("ISIM Service Table: Can't read, response code = %s" % (sw,))
# Done for this card and maybe for everything ?
print("Done !\n")
print "Done !\n"

View File

@@ -1,108 +0,0 @@
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
""" pySim: card handler utilities
"""
#
# (C) 2019 by Sysmocom s.f.m.c. GmbH
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import subprocess
import sys
import yaml
# Manual card handler: User is prompted to insert/remove card from the reader.
class card_handler:
sl = None
def __init__(self, sl):
self.sl = sl
def get(self, first = False):
print("Ready for Programming: Insert card now (or CTRL-C to cancel)")
self.sl.wait_for_card(newcardonly=not first)
def error(self):
print("Programming failed: Remove card from reader")
print("")
def done(self):
print("Programming successful: Remove card from reader")
print("")
# Automatic card handler: A machine is used to handle the cards.
class card_handler_auto:
sl = None
cmds = None
verbose = True
def __init__(self, sl, config_file):
print("Card handler Config-file: " + str(config_file))
self.sl = sl
with open(config_file) as cfg:
self.cmds = yaml.load(cfg, Loader=yaml.FullLoader)
self.verbose = (self.cmds.get('verbose') == True)
def __print_outout(self,out):
print("")
print("Card handler output:")
print("---------------------8<---------------------")
stdout = out[0].strip()
if len(stdout) > 0:
print("stdout:")
print(stdout)
stderr = out[1].strip()
if len(stderr) > 0:
print("stderr:")
print(stderr)
print("---------------------8<---------------------")
print("")
def __exec_cmd(self, command):
print("Card handler Commandline: " + str(command))
proc = subprocess.Popen([command], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out = proc.communicate()
rc = proc.returncode
if rc != 0 or self.verbose:
self.__print_outout(out)
if rc != 0:
print("")
print("Error: Card handler failure! (rc=" + str(rc) + ")")
sys.exit(rc)
def get(self, first = False):
print("Ready for Programming: Transporting card into the reader-bay...")
self.__exec_cmd(self.cmds['get'])
self.sl.connect()
def error(self):
print("Programming failed: Transporting card to the error-bin...")
self.__exec_cmd(self.cmds['error'])
print("")
def done(self):
print("Programming successful: Transporting card into the collector bin...")
self.__exec_cmd(self.cmds['done'])
print("")

View File

@@ -24,7 +24,6 @@
#
from pySim.ts_51_011 import EF, DF
from pySim.ts_31_102 import EF_USIM_ADF_map
from pySim.utils import *
from smartcard.util import toBytes
@@ -33,22 +32,10 @@ class Card(object):
def __init__(self, scc):
self._scc = scc
self._adm_chv_num = 4
self._aids = []
def reset(self):
self._scc.reset_card()
def erase(self):
print("warning: erasing is not supported for specified card type!")
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):
'''
Authenticate with ADM key
@@ -78,13 +65,6 @@ class Card(object):
data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4))
return sw
def read_hplmn_act(self):
(res, sw) = self._scc.read_binary(EF['HPLMNAcT'])
if sw == '9000':
return (format_xplmn_w_act(res), sw)
else:
return (None, sw)
def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
"""
Update Home PLMN with access technology bit-field
@@ -96,54 +76,40 @@ class Card(object):
access_tech = 'FFFF' # All technologues selected, even Reserved for Future Use ones
"""
# get size and write EF.HPLMNwAcT
data = self._scc.read_binary(EF['HPLMNwAcT'], length=None, offset=0)
size = len(data[0]) // 2
r = self._scc.select_file(EF['HPLMNwAcT'])
size = int(r[-1][4:8], 16)
hplmn = enc_plmn(mcc, mnc)
content = hplmn + access_tech
data, sw = self._scc.update_binary(EF['HPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
data, sw = self._scc.update_binary(EF['HPLMNwAcT'], content + 'ffffff0000' * (size/5-1))
return sw
def read_oplmn_act(self):
(res, sw) = self._scc.read_binary(EF['OPLMNwAcT'])
if sw == '9000':
return (format_xplmn_w_act(res), sw)
else:
return (None, sw)
def update_oplmn_act(self, mcc, mnc, access_tech='FFFF'):
"""
See note in update_hplmn_act()
See note in update_hplmn_act()
"""
# get size and write EF.OPLMNwAcT
data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
size = len(data[0]) // 2
data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
size = len(data[0])/2
hplmn = enc_plmn(mcc, mnc)
content = hplmn + access_tech
data, sw = self._scc.update_binary(EF['OPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
data, sw = self._scc.update_binary(EF['OPLMNwAcT'], content + 'ffffff0000' * (size/5-1))
return sw
def read_plmn_act(self):
(res, sw) = self._scc.read_binary(EF['PLMNwAcT'])
if sw == '9000':
return (format_xplmn_w_act(res), sw)
else:
return (None, sw)
def update_plmn_act(self, mcc, mnc, access_tech='FFFF'):
"""
See note in update_hplmn_act()
See note in update_hplmn_act()
"""
# get size and write EF.PLMNwAcT
data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
size = len(data[0]) // 2
data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
size = len(data[0])/2
hplmn = enc_plmn(mcc, mnc)
content = hplmn + access_tech
data, sw = self._scc.update_binary(EF['PLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
data, sw = self._scc.update_binary(EF['PLMNwAcT'], content + 'ffffff0000' * (size/5-1))
return sw
def update_plmnsel(self, mcc, mnc):
data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
size = len(data[0]) // 2
def update_plmnsel(self, mcc, mnc):
data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
size = len(data[0])/2
hplmn = enc_plmn(mcc, mnc)
data, sw = self._scc.update_binary(EF['PLMNsel'], hplmn + 'ff' * (size-3))
return sw
@@ -153,20 +119,16 @@ class Card(object):
return sw
def update_ad(self, mnc):
#See also: 3GPP TS 31.102, chapter 4.2.18
mnclen = len(str(mnc))
if mnclen == 1:
mnclen = 2
if mnclen > 3:
#See also: 3GPP TS 31.102, chapter 4.2.18
mnclen = len(str(mnc))
if mnclen == 1:
mnclen = 2
if mnclen > 3:
raise RuntimeError('unable to calculate proper mnclen')
data, sw = self._scc.read_binary(EF['AD'], length=None, offset=0)
# Reset contents to EF.AD in case the file is uninintalized
if data.lower() == "ffffffff":
data = "00000000"
content = data[0:6] + "%02X" % mnclen
data = self._scc.read_binary(EF['AD'], length=None, offset=0)
size = len(data[0])/2
content = data[0][0:6] + "%02X" % mnclen
data, sw = self._scc.update_binary(EF['AD'], content)
return sw
@@ -182,113 +144,6 @@ class Card(object):
data, sw = self._scc.update_binary(EF['SPN'], rpad(content, 32))
return sw
def read_binary(self, ef, length=None, offset=0):
ef_path = ef in EF and EF[ef] or ef
return self._scc.read_binary(ef_path, length, offset)
def read_record(self, ef, rec_no):
ef_path = ef in EF and EF[ef] or ef
return self._scc.read_record(ef_path, rec_no)
def read_gid1(self):
(res, sw) = self._scc.read_binary(EF['GID1'])
if sw == '9000':
return (res, sw)
else:
return (None, sw)
def read_msisdn(self):
(res, sw) = self._scc.read_record(EF['MSISDN'], 1)
if sw == '9000':
return (dec_msisdn(res), sw)
else:
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
def read_aids(self):
try:
# Find out how many records the EF.DIR has
# and store all the AIDs in the UICC
rec_cnt = self._scc.record_count(EF['DIR'])
for i in range(0, rec_cnt):
rec = self._scc.read_record(EF['DIR'], i + 1)
if (rec[0][0:2], rec[0][4:6]) == ('61', '4f') and len(rec[0]) > 12 \
and rec[0][8:8 + int(rec[0][6:8], 16) * 2] not in self._aids:
self._aids.append(rec[0][8:8 + int(rec[0][6:8], 16) * 2])
except Exception as e:
print("Can't read AIDs from SIM -- %s" % (str(e),))
# Select ADF.U/ISIM in the Card using its full AID
def select_adf_by_aid(self, adf="usim"):
# Check for valid ADF name
if adf not in ["usim", "isim"]:
return None
# First (known) halves of the U/ISIM AID
aid_map = {}
aid_map["usim"] = "a0000000871002"
aid_map["isim"] = "a0000000871004"
for aid in self._aids:
if aid_map[adf] in aid:
(res, sw) = self._scc.select_adf(aid)
return sw
return None
# Erase the contents of a file
def erase_binary(self, ef):
len = self._scc.binary_size(ef)
self._scc.update_binary(ef, "ff" * len, offset=0, verify=True)
# Erase the contents of a single record
def erase_record(self, ef, rec_no):
len = self._scc.record_size(ef)
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):
"""
@@ -296,7 +151,7 @@ class _MagicSimBase(Card):
each possible provider uses a specific record number in each EF. The
indexes used are ( where N is the number of providers supported ) :
- [2 .. N+1] for the operator name
- [1 .. N] for the programable EFs
- [1 .. N] for the programable EFs
* 3f00/7f4d/8f0c : Operator Name
@@ -520,8 +375,8 @@ class GrcardSim(Card):
#self._scc.verify_chv(4, h2b("4444444444444444"))
# Authenticate using ADM PIN 5
if p['pin_adm']:
pin = h2b(p['pin_adm'])
if p['adm1']:
pin = h2b(p['adm1'])
else:
pin = h2b("4444444444444444")
self._scc.verify_chv(5, pin)
@@ -539,7 +394,7 @@ class GrcardSim(Card):
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
# EF.SMSP
if p.get('smsp'):
if p.get('smsp'):
r = self._scc.select_file(['3f00', '7f10', '6f42'])
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
@@ -560,6 +415,8 @@ class GrcardSim(Card):
# FIXME: EF.MSISDN
def erase(self):
return
class SysmoSIMgr1(GrcardSim):
"""
@@ -569,7 +426,7 @@ class SysmoSIMgr1(GrcardSim):
"""
name = 'sysmosim-gr1'
@classmethod
@classmethod
def autodetect(kls, scc):
try:
# Look for ATR
@@ -579,7 +436,7 @@ class SysmoSIMgr1(GrcardSim):
return None
return None
class SysmoUSIMgr1(UsimCard):
class SysmoUSIMgr1(Card):
"""
sysmocom sysmoUSIM-GR1
"""
@@ -604,6 +461,9 @@ class SysmoUSIMgr1(UsimCard):
)
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
def erase(self):
return
class SysmoSIMgr2(Card):
"""
@@ -635,8 +495,8 @@ class SysmoSIMgr2(Card):
# P1: 3A for PIN, 3B for PUK
# P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
# P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
if p['pin_adm']:
pin = h2b(p['pin_adm'])
if p['adm1']:
pin = p['adm1']
else:
pin = h2b("4444444444444444")
@@ -676,11 +536,13 @@ class SysmoSIMgr2(Card):
r = self._scc.select_file(['3f00', '7f10'])
# write EF.SMSP
if p.get('smsp'):
if p.get('smsp'):
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
def erase(self):
return
class SysmoUSIMSJS1(UsimCard):
class SysmoUSIMSJS1(Card):
"""
sysmocom sysmoUSIM-SJS1
"""
@@ -705,9 +567,9 @@ class SysmoUSIMSJS1(UsimCard):
def program(self, p):
# authenticate as ADM using default key (written on the card..)
if not p['pin_adm']:
if not p['adm1']:
raise ValueError("Please provide a PIN-ADM as there is no default one")
self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
self._scc.verify_chv(0x0A, p['adm1'])
# select MF
r = self._scc.select_file(['3f00'])
@@ -726,43 +588,29 @@ class SysmoUSIMSJS1(UsimCard):
content = "01" + p['opc']
data, sw = self._scc.update_binary('00F7', content)
# set Service Provider Name
if p.get('name') is not None:
content = enc_spn(p['name'], True, True)
data, sw = self._scc.update_binary('6F46', rpad(content, 32))
if p.get('acc') is not None:
self.update_acc(p['acc'])
# write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
# EF.PLMNsel
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmnsel(p['mcc'], p['mnc'])
if sw != '9000':
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmnsel(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming PLMNsel failed with code %s"%sw)
# EF.PLMNwAcT
if p.get('mcc') and p.get('mnc'):
# EF.PLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming PLMNwAcT failed with code %s"%sw)
# EF.OPLMNwAcT
if p.get('mcc') and p.get('mnc'):
# EF.OPLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming OPLMNwAcT failed with code %s"%sw)
# EF.HPLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_hplmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming HPLMNwAcT failed with code %s"%sw)
# EF.AD
if p.get('mcc') and p.get('mnc'):
# EF.AD
if p.get('mcc') and p.get('mnc'):
sw = self.update_ad(p['mnc'])
if sw != '9000':
print("Programming AD failed with code %s"%sw)
@@ -772,16 +620,8 @@ class SysmoUSIMSJS1(UsimCard):
r = self._scc.select_file(['3f00', '7f10'])
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'])
data = 'ff' * 20 + msisdn + 'ff' * 2
r = self._scc.select_file(['3f00', '7f10'])
data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
def erase(self):
return
class FairwavesSIM(Card):
@@ -796,7 +636,7 @@ class FairwavesSIM(Card):
3F00/7F20/FF02: Ki
"""
name = 'Fairwaves-SIM'
name = 'Fairwaves SIM'
# Propriatary files
_EF_num = {
'Ki': 'FF02',
@@ -924,13 +764,17 @@ class FairwavesSIM(Card):
if sw != '9000':
print("Programming ACC failed with code %s"%sw)
def erase(self):
return
class OpenCellsSim(Card):
"""
OpenCellsSim
"""
name = 'OpenCells-SIM'
name = 'OpenCells SIM'
def __init__(self, ssc):
super(OpenCellsSim, self).__init__(ssc)
@@ -1004,28 +848,28 @@ class WavemobileSim(Card):
if sw != '9000':
raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
# EF.ICCID
# TODO: Add programming of the ICCID
if p.get('iccid'):
# EF.ICCID
# TODO: Add programming of the ICCID
if p.get('iccid'):
print("Warning: Programming of the ICCID is not implemented for this type of card.")
# KI (Presumably a propritary file)
# TODO: Add programming of KI
if p.get('ki'):
# KI (Presumably a propritary file)
# TODO: Add programming of KI
if p.get('ki'):
print("Warning: Programming of the KI is not implemented for this type of card.")
# OPc (Presumably a propritary file)
# TODO: Add programming of OPc
if p.get('opc'):
# OPc (Presumably a propritary file)
# TODO: Add programming of OPc
if p.get('opc'):
print("Warning: Programming of the OPc is not implemented for this type of card.")
# EF.SMSP
# EF.SMSP
if p.get('smsp'):
sw = self.update_smsp(p['smsp'])
if sw != '9000':
print("Programming SMSP failed with code %s"%sw)
# EF.IMSI
# EF.IMSI
if p.get('imsi'):
sw = self.update_imsi(p['imsi'])
if sw != '9000':
@@ -1038,162 +882,39 @@ class WavemobileSim(Card):
print("Programming ACC failed with code %s"%sw)
# EF.PLMNsel
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmnsel(p['mcc'], p['mnc'])
if sw != '9000':
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmnsel(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming PLMNsel failed with code %s"%sw)
# EF.PLMNwAcT
if p.get('mcc') and p.get('mnc'):
# EF.PLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming PLMNwAcT failed with code %s"%sw)
# EF.OPLMNwAcT
if p.get('mcc') and p.get('mnc'):
# EF.OPLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming OPLMNwAcT failed with code %s"%sw)
# EF.AD
if p.get('mcc') and p.get('mnc'):
# EF.AD
if p.get('mcc') and p.get('mnc'):
sw = self.update_ad(p['mnc'])
if sw != '9000':
print("Programming AD failed with code %s"%sw)
return None
return None
class SysmoISIMSJA2(UsimCard):
"""
sysmocom sysmoISIM-SJA2
"""
name = 'sysmoISIM-SJA2'
def __init__(self, ssc):
super(SysmoISIMSJA2, self).__init__(ssc)
self._scc.cla_byte = "00"
self._scc.sel_ctrl = "0004" #request an FCP
@classmethod
def autodetect(kls, scc):
try:
# Try card model #1
atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9"
if scc.get_atr() == toBytes(atr):
return kls(scc)
# Try card model #2
atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2"
if scc.get_atr() == toBytes(atr):
return kls(scc)
# Try card model #3
atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"
if scc.get_atr() == toBytes(atr):
return kls(scc)
except:
return None
return None
def program(self, p):
# authenticate as ADM using default key (written on the card..)
if not p['pin_adm']:
raise ValueError("Please provide a PIN-ADM as there is no default one")
self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
# This type of card does not allow to reprogram the ICCID.
# Reprogramming the ICCID would mess up the card os software
# license management, so the ICCID must be kept at its factory
# setting!
if p.get('iccid'):
print("Warning: Programming of the ICCID is not implemented for this type of card.")
# select DF_GSM
self._scc.select_file(['7f20'])
# write EF.IMSI
if p.get('imsi'):
self._scc.update_binary('6f07', enc_imsi(p['imsi']))
# EF.PLMNsel
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmnsel(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming PLMNsel failed with code %s"%sw)
# EF.PLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming PLMNwAcT failed with code %s"%sw)
# EF.OPLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming OPLMNwAcT failed with code %s"%sw)
# EF.HPLMNwAcT
if p.get('mcc') and p.get('mnc'):
sw = self.update_hplmn_act(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming HPLMNwAcT failed with code %s"%sw)
# EF.AD
if p.get('mcc') and p.get('mnc'):
sw = self.update_ad(p['mnc'])
if sw != '9000':
print("Programming AD failed with code %s"%sw)
# EF.SMSP
if p.get('smsp'):
r = self._scc.select_file(['3f00', '7f10'])
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
# update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
# hard linked to EF-USIM_AUTH_KEY)
self._scc.select_file(['3f00'])
self._scc.select_file(['a515'])
if p.get('ki'):
self._scc.update_binary('6f20', p['ki'], 1)
if p.get('opc'):
self._scc.update_binary('6f20', p['opc'], 17)
# update EF-USIM_AUTH_KEY in ADF.ISIM
self._scc.select_file(['3f00'])
aid = self.read_aid(isim = True)
if (aid):
self._scc.select_adf(aid)
if p.get('ki'):
self._scc.update_binary('af20', p['ki'], 1)
if p.get('opc'):
self._scc.update_binary('af20', p['opc'], 17)
self._scc.select_file(['3f00'])
aid = self.read_aid()
if (aid):
# update EF-USIM_AUTH_KEY in ADF.USIM
self._scc.select_adf(aid)
if p.get('ki'):
self._scc.update_binary('af20', p['ki'], 1)
if p.get('opc'):
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)
def erase(self):
return
# In order for autodetection ...
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2 ]
FairwavesSIM, OpenCellsSim, WavemobileSim ]
def card_autodetect(scc):
for kls in _cards_classes:
@@ -1202,31 +923,3 @@ def card_autodetect(scc):
card.reset()
return card
return None
def card_detect(ctype, scc):
# Detect type if needed
card = None
ctypes = dict([(kls.name, kls) for kls in _cards_classes])
if ctype in ("auto", "auto_once"):
for kls in _cards_classes:
card = kls.autodetect(scc)
if card:
print("Autodetected card type: %s" % card.name)
card.reset()
break
if card is None:
print("Autodetection failed")
return None
if ctype == "auto_once":
ctype = card.name
elif ctype in ctypes:
card = ctypes[ctype](scc)
else:
raise ValueError("Unknown card type: %s" % ctype)
return card

View File

@@ -30,11 +30,11 @@ class SimCardCommands(object):
self._cla_byte = "a0"
self.sel_ctrl = "0000"
# Extract a single FCP item from TLV
def __parse_fcp(self, fcp):
# Get file size from FCP
def __get_len_from_tlv(self, fcp):
# see also: ETSI TS 102 221, chapter 11.1.1.3.1 Response for MF,
# DF or ADF
from pytlv.TLV import TLV
from pytlv.TLV import TLV
tlvparser = TLV(['82', '83', '84', 'a5', '8a', '8b', '8c', '80', 'ab', 'c6', '81', '88'])
# pytlv is case sensitive!
@@ -49,39 +49,37 @@ class SimCardCommands(object):
# what we get in the length field.
# See also ETSI TS 102 221, chapter 11.1.1.3.0 Base coding.
exp_tlv_len = int(fcp[2:4], 16)
if len(fcp[4:]) // 2 == exp_tlv_len:
if len(fcp[4:])/2 == exp_tlv_len:
skip = 4
else:
exp_tlv_len = int(fcp[2:6], 16)
if len(fcp[4:]) // 2 == exp_tlv_len:
if len(fcp[4:])/2 == exp_tlv_len:
skip = 6
# Skip FCP tag and length
tlv = fcp[skip:]
return tlvparser.parse(tlv)
tlv_parsed = tlvparser.parse(tlv)
# Tell the length of a record by the card response
# USIMs respond with an FCP template, which is different
# from what SIMs responds. See also:
# USIM: ETSI TS 102 221, chapter 11.1.1.3 Response Data
# SIM: GSM 11.11, chapter 9.2.1 SELECT
return int(tlv_parsed['80'], 16)
# Tell the length of a record by the card response
# USIMs respond with an FCP template, which is different
# from what SIMs responds. See also:
# USIM: ETSI TS 102 221, chapter 11.1.1.3 Response Data
# SIM: GSM 11.11, chapter 9.2.1 SELECT
def __record_len(self, r):
if self.sel_ctrl == "0004":
tlv_parsed = self.__parse_fcp(r[-1])
file_descriptor = tlv_parsed['82']
# See also ETSI TS 102 221, chapter 11.1.1.4.3 File Descriptor
return int(file_descriptor[4:8], 16)
else:
return int(r[-1][28:30], 16)
if self.sel_ctrl == "0004":
return self.__get_len_from_tlv(r[-1])
else:
return int(r[-1][28:30], 16)
# Tell the length of a binary file. See also comment
# above.
# Tell the length of a binary file. See also comment
# above.
def __len(self, r):
if self.sel_ctrl == "0004":
tlv_parsed = self.__parse_fcp(r[-1])
return int(tlv_parsed['80'], 16)
else:
return int(r[-1][4:8], 16)
if self.sel_ctrl == "0004":
return self.__get_len_from_tlv(r[-1])
else:
return int(r[-1][4:8], 16)
def get_atr(self):
return self._tp.get_atr()
@@ -100,85 +98,51 @@ class SimCardCommands(object):
def sel_ctrl(self, 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):
rv = []
if type(dir_list) is not list:
dir_list = [dir_list]
for i in dir_list:
data, sw = self._tp.send_apdu_checksw(self.cla_byte + "a4" + self.sel_ctrl + "02" + i)
rv.append(data)
return rv
def select_adf(self, aid):
aidlen = ("0" + format(len(aid) // 2, 'x'))[-2:]
return self._tp.send_apdu_checksw(self.cla_byte + "a4" + "0404" + aidlen + aid)
def read_binary(self, ef, length=None, offset=0):
if not hasattr(type(ef), '__iter__'):
ef = [ef]
r = self.select_file(ef)
if len(r[-1]) == 0:
return (None, None)
if length is None:
length = self.__len(r) - offset
total_data = ''
while offset < length:
chunk_len = min(255, length-offset)
pdu = self.cla_byte + 'b0%04x%02x' % (offset, chunk_len)
data,sw = self._tp.send_apdu(pdu)
if sw == '9000':
total_data += data
offset += chunk_len
else:
raise ValueError('Failed to read (offset %d)' % (offset))
return total_data, sw
pdu = self.cla_byte + 'b0%04x%02x' % (offset, (min(256, length) & 0xff))
return self._tp.send_apdu(pdu)
def update_binary(self, ef, data, offset=0, verify=False):
def update_binary(self, ef, data, offset=0):
if not hasattr(type(ef), '__iter__'):
ef = [ef]
self.select_file(ef)
pdu = self.cla_byte + 'd6%04x%02x' % (offset, len(data) // 2) + data
res = self._tp.send_apdu_checksw(pdu)
if verify:
self.verify_binary(ef, data, offset)
return res
def verify_binary(self, ef, data, offset=0):
res = self.read_binary(ef, len(data) // 2, offset)
if res[0].lower() != data.lower():
raise ValueError('Binary verification failed (expected %s, got %s)' % (data.lower(), res[0].lower()))
pdu = self.cla_byte + 'd6%04x%02x' % (offset, len(data)/2) + data
return self._tp.send_apdu_checksw(pdu)
def read_record(self, ef, rec_no):
if not hasattr(type(ef), '__iter__'):
ef = [ef]
r = self.select_file(ef)
rec_length = self.__record_len(r)
pdu = self.cla_byte + 'b2%02x04%02x' % (rec_no, rec_length)
return self._tp.send_apdu(pdu)
def update_record(self, ef, rec_no, data, force_len=False, verify=False):
def update_record(self, ef, rec_no, data, force_len=False):
if not hasattr(type(ef), '__iter__'):
ef = [ef]
r = self.select_file(ef)
if not force_len:
rec_length = self.__record_len(r)
if (len(data) // 2 != rec_length):
raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data) // 2))
if (len(data)/2 != rec_length):
raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data)/2))
else:
rec_length = len(data) // 2
rec_length = len(data)/2
pdu = (self.cla_byte + 'dc%02x04%02x' % (rec_no, rec_length)) + data
res = self._tp.send_apdu_checksw(pdu)
if verify:
self.verify_record(ef, rec_no, data)
return res
def verify_record(self, ef, rec_no, data):
res = self.read_record(ef, rec_no)
if res[0].lower() != data.lower():
raise ValueError('Record verification failed (expected %s, got %s)' % (data.lower(), res[0].lower()))
return self._tp.send_apdu_checksw(pdu)
def record_size(self, ef):
r = self.select_file(ef)
@@ -188,10 +152,6 @@ class SimCardCommands(object):
r = self.select_file(ef)
return self.__len(r) // self.__record_len(r)
def binary_size(self, ef):
r = self.select_file(ef)
return self.__len(r)
def run_gsm(self, rand):
if len(rand) != 32:
raise ValueError('Invalid rand')

View File

@@ -23,17 +23,14 @@
from __future__ import absolute_import
try:
# This is for compatibility with python 2 and 3
from exceptions import Exception
except:
import exceptions
class NoCardError(exceptions.Exception):
pass
class NoCardError(Exception):
class ProtocolError(exceptions.Exception):
pass
class ProtocolError(Exception):
pass
class ReaderError(Exception):
class ReaderError(exceptions.Exception):
pass

View File

@@ -28,7 +28,7 @@ class LinkBase(object):
timeout : Maximum wait time (None=no timeout)
newcardonly : Should we wait for a new card, or an already
inserted one ?
inserted one ?
"""
pass
@@ -52,8 +52,8 @@ class LinkBase(object):
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
return : tuple(data, sw), where
data : string (in hex) of returned data (ex. "074F4EFFFF")
sw : string (in hex) of status word (ex. "9000")
data : string (in hex) of returned data (ex. "074F4EFFFF")
sw : string (in hex) of status word (ex. "9000")
"""
pass
@@ -62,8 +62,8 @@ class LinkBase(object):
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
return : tuple(data, sw), where
data : string (in hex) of returned data (ex. "074F4EFFFF")
sw : string (in hex) of status word (ex. "9000")
data : string (in hex) of returned data (ex. "074F4EFFFF")
sw : string (in hex) of status word (ex. "9000")
"""
data, sw = self.send_apdu_raw(pdu)
@@ -84,15 +84,15 @@ class LinkBase(object):
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
sw : string of 4 hexadecimal characters (ex. "9000"). The
user may mask out certain digits using a '?' to add some
ambiguity if needed.
user may mask out certain digits using a '?' to add some
ambiguity if needed.
return : tuple(data, sw), where
data : string (in hex) of returned data (ex. "074F4EFFFF")
sw : string (in hex) of status word (ex. "9000")
data : string (in hex) of returned data (ex. "074F4EFFFF")
sw : string (in hex) of status word (ex. "9000")
"""
rv = self.send_apdu(pdu)
# Create a masked version of the returned status word
# Create a masked version of the returned status word
sw_masked = ""
for i in range(0, 4):
if sw.lower()[i] == '?':

View File

@@ -1,126 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
""" pySim: Transport Link for 3GPP TS 27.007 compliant modems
"""
# Copyright (C) 2020 Vadim Yanitskiy <axilirator@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import absolute_import
import logging as log
import serial
import time
import re
from pySim.transport import LinkBase
from pySim.exceptions import *
# HACK: if somebody needs to debug this thing
# log.root.setLevel(log.DEBUG)
class ModemATCommandLink(LinkBase):
def __init__(self, device='/dev/ttyUSB0', baudrate=115200):
self._sl = serial.Serial(device, baudrate, timeout=5)
self._device = device
self._atr = None
# Trigger initial reset
self.reset_card()
def __del__(self):
self._sl.close()
def send_at_cmd(self, cmd):
# Convert from string to bytes, if needed
bcmd = cmd if type(cmd) is bytes else cmd.encode()
bcmd += b'\r'
# Send command to the modem
log.debug('Sending AT command: %s' % cmd)
try:
wlen = self._sl.write(bcmd)
assert(wlen == len(bcmd))
except:
raise ReaderError('Failed to send AT command: %s' % cmd)
# Give the modem some time...
time.sleep(0.3)
# Read the response
try:
# Skip characters sent back
self._sl.read(wlen)
# Read the rest
rsp = self._sl.read_all()
# Strip '\r\n'
rsp = rsp.strip()
# Split into a list
rsp = rsp.split(b'\r\n\r\n')
except:
raise ReaderError('Failed parse response to AT command: %s' % cmd)
log.debug('Got response from modem: %s' % rsp)
return rsp
def reset_card(self):
# Make sure that we can talk to the modem
if self.send_at_cmd('AT') != [b'OK']:
raise ReaderError('Failed to connect to modem')
# Reset the modem, just to be sure
if self.send_at_cmd('ATZ') != [b'OK']:
raise ReaderError('Failed to reset the modem')
# Make sure that generic SIM access is supported
if self.send_at_cmd('AT+CSIM=?') != [b'OK']:
raise ReaderError('The modem does not seem to support SIM access')
log.info('Modem at \'%s\' is ready!' % self._device)
def connect(self):
pass # Nothing to do really ...
def disconnect(self):
pass # Nothing to do really ...
def wait_for_card(self, timeout=None, newcardonly=False):
pass # Nothing to do really ...
def send_apdu_raw(self, pdu):
# Prepare the command as described in 8.17
cmd = 'AT+CSIM=%d,\"%s\"' % (len(pdu), pdu)
# Send AT+CSIM command to the modem
# TODO: also handle +CME ERROR: <err>
rsp = self.send_at_cmd(cmd)
if len(rsp) != 2 or rsp[-1] != b'OK':
raise ReaderError('APDU transfer failed: %s' % str(rsp))
rsp = rsp[0] # Get rid of b'OK'
# Make sure that the response has format: b'+CSIM: %d,\"%s\"'
try:
result = re.match(b'\+CSIM: (\d+),\"([0-9A-F]+)\"', rsp)
(rsp_pdu_len, rsp_pdu) = result.groups()
except:
raise ReaderError('Failed to parse response from modem: %s' % rsp)
# TODO: make sure we have at least SW
data = rsp_pdu[:-4].decode()
sw = rsp_pdu[-4:].decode()
return data, sw

View File

@@ -22,7 +22,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from smartcard.CardConnection import CardConnection
from smartcard.CardRequest import CardRequest
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException
from smartcard.System import readers
@@ -53,10 +52,7 @@ class PcscSimLink(LinkBase):
def connect(self):
try:
# Explicitly select T=0 communication protocol
self._con.connect(CardConnection.T0_protocol)
except CardConnectionException:
raise ProtocolError()
self._con.connect()
except NoCardException:
raise NoCardError()
@@ -67,8 +63,11 @@ class PcscSimLink(LinkBase):
self._con.disconnect()
def reset_card(self):
self.disconnect()
self.connect()
self._con.disconnect()
try:
self._con.connect()
except NoCardException:
raise NoCardError()
return 1
def send_apdu_raw(self, pdu):

View File

@@ -162,7 +162,7 @@ class SerialSimLink(LinkBase):
def _dbg_print(self, s):
if self._debug:
print(s)
print s
def _tx_byte(self, b):
self._sl.write(b)
@@ -213,7 +213,7 @@ class SerialSimLink(LinkBase):
self._tx_string(pdu[5:])
# Receive data (including SW !)
# length = [P3 - tx_data (=len(pdu)-len(hdr)) + 2 (SW1//2) ]
# length = [P3 - tx_data (=len(pdu)-len(hdr)) + 2 (SW1/2) ]
to_recv = data_len - len(pdu) + 5 + 2
data = ''

View File

@@ -1,248 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Various constants from ETSI TS 131 102
"""
#
# Copyright (C) 2020 Supreeth Herle <herlesupreeth@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Mapping between USIM Service Number and its description
EF_UST_map = {
1: 'Local Phone Book',
2: 'Fixed Dialling Numbers (FDN)',
3: 'Extension 2',
4: 'Service Dialling Numbers (SDN)',
5: 'Extension3',
6: 'Barred Dialling Numbers (BDN)',
7: 'Extension4',
8: 'Outgoing Call Information (OCI and OCT)',
9: 'Incoming Call Information (ICI and ICT)',
10: 'Short Message Storage (SMS)',
11: 'Short Message Status Reports (SMSR)',
12: 'Short Message Service Parameters (SMSP)',
13: 'Advice of Charge (AoC)',
14: 'Capability Configuration Parameters 2 (CCP2)',
15: 'Cell Broadcast Message Identifier',
16: 'Cell Broadcast Message Identifier Ranges',
17: 'Group Identifier Level 1',
18: 'Group Identifier Level 2',
19: 'Service Provider Name',
20: 'User controlled PLMN selector with Access Technology',
21: 'MSISDN',
22: 'Image (IMG)',
23: 'Support of Localised Service Areas (SoLSA)',
24: 'Enhanced Multi-Level Precedence and Pre-emption Service',
25: 'Automatic Answer for eMLPP',
26: 'RFU',
27: 'GSM Access',
28: 'Data download via SMS-PP',
29: 'Data download via SMS-CB',
30: 'Call Control by USIM',
31: 'MO-SMS Control by USIM',
32: 'RUN AT COMMAND command',
33: 'shall be set to 1',
34: 'Enabled Services Table',
35: 'APN Control List (ACL)',
36: 'Depersonalisation Control Keys',
37: 'Co-operative Network List',
38: 'GSM security context',
39: 'CPBCCH Information',
40: 'Investigation Scan',
41: 'MexE',
42: 'Operator controlled PLMN selector with Access Technology',
43: 'HPLMN selector with Access Technology',
44: 'Extension 5',
45: 'PLMN Network Name',
46: 'Operator PLMN List',
47: 'Mailbox Dialling Numbers',
48: 'Message Waiting Indication Status',
49: 'Call Forwarding Indication Status',
50: 'Reserved and shall be ignored',
51: 'Service Provider Display Information',
52: 'Multimedia Messaging Service (MMS)',
53: 'Extension 8',
54: 'Call control on GPRS by USIM',
55: 'MMS User Connectivity Parameters',
56: 'Network\'s indication of alerting in the MS (NIA)',
57: 'VGCS Group Identifier List (EFVGCS and EFVGCSS)',
58: 'VBS Group Identifier List (EFVBS and EFVBSS)',
59: 'Pseudonym',
60: 'User Controlled PLMN selector for I-WLAN access',
61: 'Operator Controlled PLMN selector for I-WLAN access',
62: 'User controlled WSID list',
63: 'Operator controlled WSID list',
64: 'VGCS security',
65: 'VBS security',
66: 'WLAN Reauthentication Identity',
67: 'Multimedia Messages Storage',
68: 'Generic Bootstrapping Architecture (GBA)',
69: 'MBMS security',
70: 'Data download via USSD and USSD application mode',
71: 'Equivalent HPLMN',
72: 'Additional TERMINAL PROFILE after UICC activation',
73: 'Equivalent HPLMN Presentation Indication',
74: 'Last RPLMN Selection Indication',
75: 'OMA BCAST Smart Card Profile',
76: 'GBA-based Local Key Establishment Mechanism',
77: 'Terminal Applications',
78: 'Service Provider Name Icon',
79: 'PLMN Network Name Icon',
80: 'Connectivity Parameters for USIM IP connections',
81: 'Home I-WLAN Specific Identifier List',
82: 'I-WLAN Equivalent HPLMN Presentation Indication',
83: 'I-WLAN HPLMN Priority Indication',
84: 'I-WLAN Last Registered PLMN',
85: 'EPS Mobility Management Information',
86: 'Allowed CSG Lists and corresponding indications',
87: 'Call control on EPS PDN connection by USIM',
88: 'HPLMN Direct Access',
89: 'eCall Data',
90: 'Operator CSG Lists and corresponding indications',
91: 'Support for SM-over-IP',
92: 'Support of CSG Display Control',
93: 'Communication Control for IMS by USIM',
94: 'Extended Terminal Applications',
95: 'Support of UICC access to IMS',
96: 'Non-Access Stratum configuration by USIM',
97: 'PWS configuration by USIM',
98: 'RFU',
99: 'URI support by UICC',
100: 'Extended EARFCN support',
101: 'ProSe',
102: 'USAT Application Pairing',
103: 'Media Type support',
104: 'IMS call disconnection cause',
105: 'URI support for MO SHORT MESSAGE CONTROL',
106: 'ePDG configuration Information support',
107: 'ePDG configuration Information configured',
108: 'ACDC support',
109: 'MCPTT',
110: 'ePDG configuration Information for Emergency Service support',
111: 'ePDG configuration Information for Emergency Service configured',
}
LOCI_STATUS_map = {
0: 'updated',
1: 'not updated',
2: 'plmn not allowed',
3: 'locatation area not allowed'
}
EF_USIM_ADF_map = {
'LI': '6F05',
'ARR': '6F06',
'IMSI': '6F07',
'Keys': '6F08',
'KeysPS': '6F09',
'DCK': '6F2C',
'HPPLMN': '6F31',
'CNL': '6F32',
'ACMmax': '6F37',
'UST': '6F38',
'ACM': '6F39',
'FDN': '6F3B',
'SMS': '6F3C',
'GID1': '6F3E',
'GID2': '6F3F',
'MSISDN': '6F40',
'PUCT': '6F41',
'SMSP': '6F42',
'SMSS': '6F42',
'CBMI': '6F45',
'SPN': '6F46',
'SMSR': '6F47',
'CBMID': '6F48',
'SDN': '6F49',
'EXT2': '6F4B',
'EXT3': '6F4C',
'BDN': '6F4D',
'EXT5': '6F4E',
'CCP2': '6F4F',
'CBMIR': '6F50',
'EXT4': '6F55',
'EST': '6F56',
'ACL': '6F57',
'CMI': '6F58',
'START-HFN': '6F5B',
'THRESHOLD': '6F5C',
'PLMNwAcT': '6F60',
'OPLMNwAcT': '6F61',
'HPLMNwAcT': '6F62',
'PSLOCI': '6F73',
'ACC': '6F78',
'FPLMN': '6F7B',
'LOCI': '6F7E',
'ICI': '6F80',
'OCI': '6F81',
'ICT': '6F82',
'OCT': '6F83',
'AD': '6FAD',
'VGCS': '6FB1',
'VGCSS': '6FB2',
'VBS': '6FB3',
'VBSS': '6FB4',
'eMLPP': '6FB5',
'AAeM': '6FB6',
'ECC': '6FB7',
'Hiddenkey': '6FC3',
'NETPAR': '6FC4',
'PNN': '6FC5',
'OPL': '6FC6',
'MBDN': '6FC7',
'EXT6': '6FC8',
'MBI': '6FC9',
'MWIS': '6FCA',
'CFIS': '6FCB',
'EXT7': '6FCC',
'SPDI': '6FCD',
'MMSN': '6FCE',
'EXT8': '6FCF',
'MMSICP': '6FD0',
'MMSUP': '6FD1',
'MMSUCP': '6FD2',
'NIA': '6FD3',
'VGCSCA': '6FD4',
'VBSCA': '6FD5',
'GBAP': '6FD6',
'MSK': '6FD7',
'MUK': '6FD8',
'EHPLMN': '6FD9',
'GBANL': '6FDA',
'EHPLMNPI': '6FDB',
'LRPLMNSI': '6FDC',
'NAFKCA': '6FDD',
'SPNI': '6FDE',
'PNNI': '6FDF',
'NCP-IP': '6FE2',
'EPSLOCI': '6FE3',
'EPSNSC': '6FE4',
'UFC': '6FE6',
'UICCIARI': '6FE7',
'NASCONFIG': '6FE8',
'PWC': '6FEC',
'FDNURI': '6FED',
'BDNURI': '6FEE',
'SDNURI': '6FEF',
'IWL': '6FF0',
'IPS': '6FF1',
'IPD': '6FF2',
'ePDGId': '6FF3',
'ePDGSelection': '6FF4',
'ePDGIdEm': '6FF5',
'ePDGSelectionEm': '6FF6',
}

View File

@@ -1,46 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Various constants from ETSI TS 131 103 V14.2.0
"""
#
# Copyright (C) 2020 Supreeth Herle <herlesupreeth@gmail.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# Mapping between ISIM Service Number and its description
EF_IST_map = {
1: 'P-CSCF address',
2: 'Generic Bootstrapping Architecture (GBA)',
3: 'HTTP Digest',
4: 'GBA-based Local Key Establishment Mechanism',
5: 'Support of P-CSCF discovery for IMS Local Break Out',
6: 'Short Message Storage (SMS)',
7: 'Short Message Status Reports (SMSR)',
8: 'Support for SM-over-IP including data download via SMS-PP as defined in TS 31.111 [31]',
9: 'Communication Control for IMS by ISIM',
10: 'Support of UICC access to IMS',
11: 'URI support by UICC',
12: 'Media Type support',
13: 'IMS call disconnection cause',
14: 'URI support for MO SHORT MESSAGE CONTROL',
15: 'MCPTT',
16: 'URI support for SMS-PP DOWNLOAD as defined in 3GPP TS 31.111 [31]',
17: 'From Preferred',
18: 'IMS configuration data',
19: 'XCAP Configuration Data'
}

View File

@@ -48,7 +48,6 @@ EF_num = {
# MF
'ICCID': '2FE2',
'ELP': '2F05',
'DIR': '2F00',
# DF_TELECOM
'ADN': '6F3A',
@@ -165,7 +164,6 @@ DF = {
EF = {
'ICCID': [MF_num, EF_num['ICCID']],
'ELP': [MF_num, EF_num['ELP']],
'DIR': [MF_num, EF_num['DIR']],
'ADN': DF['TELECOM']+[EF_num['ADN']],
'FDN': DF['TELECOM']+[EF_num['FDN']],
@@ -251,66 +249,3 @@ EF = {
'MMSUP': DF['GSM']+[EF_num['MMSUP']],
'MMSUCP': DF['GSM']+[EF_num['MMSUCP']],
}
# Mapping between SIM Service Number and its description
EF_SST_map = {
1: 'CHV1 disable function',
2: 'Abbreviated Dialling Numbers (ADN)',
3: 'Fixed Dialling Numbers (FDN)',
4: 'Short Message Storage (SMS)',
5: 'Advice of Charge (AoC)',
6: 'Capability Configuration Parameters (CCP)',
7: 'PLMN selector',
8: 'RFU',
9: 'MSISDN',
10: 'Extension1',
11: 'Extension2',
12: 'SMS Parameters',
13: 'Last Number Dialled (LND)',
14: 'Cell Broadcast Message Identifier',
15: 'Group Identifier Level 1',
16: 'Group Identifier Level 2',
17: 'Service Provider Name',
18: 'Service Dialling Numbers (SDN)',
19: 'Extension3',
20: 'RFU',
21: 'VGCS Group Identifier List (EFVGCS and EFVGCSS)',
22: 'VBS Group Identifier List (EFVBS and EFVBSS)',
23: 'enhanced Multi-Level Precedence and Pre-emption Service',
24: 'Automatic Answer for eMLPP',
25: 'Data download via SMS-CB',
26: 'Data download via SMS-PP',
27: 'Menu selection',
28: 'Call control',
29: 'Proactive SIM',
30: 'Cell Broadcast Message Identifier Ranges',
31: 'Barred Dialling Numbers (BDN)',
32: 'Extension4',
33: 'De-personalization Control Keys',
34: 'Co-operative Network List',
35: 'Short Message Status Reports',
36: 'Network\'s indication of alerting in the MS',
37: 'Mobile Originated Short Message control by SIM',
38: 'GPRS',
39: 'Image (IMG)',
40: 'SoLSA (Support of Local Service Area)',
41: 'USSD string data object supported in Call Control',
42: 'RUN AT COMMAND command',
43: 'User controlled PLMN Selector with Access Technology',
44: 'Operator controlled PLMN Selector with Access Technology',
45: 'HPLMN Selector with Access Technology',
46: 'CPBCCH Information',
47: 'Investigation Scan',
48: 'Extended Capability Configuration Parameters',
49: 'MExE',
50: 'Reserved and shall be ignored',
51: 'PLMN Network Name',
52: 'Operator PLMN List',
53: 'Mailbox Dialling Numbers',
54: 'Message Waiting Indication Status',
55: 'Call Forwarding Indication Status',
56: 'Service Provider Display Information',
57: 'Multimedia Messaging Service (MMS)',
58: 'Extension 8',
59: 'MMS User Connectivity Parameters',
}

View File

@@ -35,16 +35,11 @@ def i2h(s):
return ''.join(['%02x'%(x) for x in s])
def h2s(s):
return ''.join([chr((int(x,16)<<4)+int(y,16)) for x,y in zip(s[0::2], s[1::2])
if int(x + y, 16) != 0xff])
return ''.join([chr((int(x,16)<<4)+int(y,16)) for x,y in zip(s[0::2], s[1::2]) if not (x == 'f' and y == 'f') ])
def s2h(s):
return b2h(s)
# List of bytes to string
def i2s(s):
return ''.join([chr(x) for x in s])
def swap_nibbles(s):
return ''.join([x+y for x,y in zip(s[1::2], s[0::2])])
@@ -86,8 +81,6 @@ def dec_imsi(ef):
l = int(ef[0:2], 16) * 2 # Length of the IMSI string
l = l - 1 # Encoded length byte includes oe nibble
swapped = swap_nibbles(ef[2:]).rstrip('f')
if len(swapped) < 1:
return None
oe = (int(swapped[0])>>3) & 1 # Odd (1) / Even (0)
if not oe:
# if even, only half of last byte was used
@@ -105,9 +98,7 @@ def enc_iccid(iccid):
def enc_plmn(mcc, mnc):
"""Converts integer MCC/MNC into 3 bytes for EF"""
if len(mnc) == 2:
mnc = "F%s" % mnc
return swap_nibbles("%s%s" % (mcc, mnc))
return swap_nibbles(lpad('%d' % mcc, 3) + lpad('%d' % mnc, 3))
def dec_spn(ef):
byte1 = int(ef[0:2])
@@ -125,9 +116,6 @@ def enc_spn(name, hplmn_disp=False, oplmn_disp=False):
def hexstr_to_fivebytearr(s):
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
def dec_mcc_from_plmn(plmn):
ia = h2i(plmn)
@@ -136,7 +124,10 @@ def dec_mcc_from_plmn(plmn):
digit3 = ia[1] & 0x0F # 2nd byte, LSB
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
return 0xFFF # 4095
return derive_mcc(digit1, digit2, digit3)
mcc = digit1 * 100
mcc += digit2 * 10
mcc += digit3
return mcc
def dec_mnc_from_plmn(plmn):
ia = h2i(plmn)
@@ -145,7 +136,16 @@ def dec_mnc_from_plmn(plmn):
digit3 = (ia[1] & 0xF0) >> 4 # 2nd byte, MSB
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
return 0xFFF # 4095
return derive_mnc(digit1, digit2, digit3)
mnc = 0
# signifies two digit MNC
if digit3 == 0xF:
mnc += digit1 * 10
mnc += digit2
else:
mnc += digit1 * 100
mnc += digit2 * 10
mnc += digit3
return mnc
def dec_act(twohexbytes):
act_list = [
@@ -182,56 +182,7 @@ def format_xplmn_w_act(hexstr):
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
rec_str = "unused"
else:
rec_str = "MCC: %03d MNC: %03d AcT: %s" % (rec_info['mcc'], rec_info['mnc'], ", ".join(rec_info['act']))
s += "\t%s # %s\n" % (rec_data, rec_str)
return s
def dec_loci(hexstr):
res = {'tmsi': '', 'mcc': 0, 'mnc': 0, 'lac': '', 'status': 0}
res['tmsi'] = hexstr[:8]
res['mcc'] = dec_mcc_from_plmn(hexstr[8:14])
res['mnc'] = dec_mnc_from_plmn(hexstr[8:14])
res['lac'] = hexstr[14:18]
res['status'] = h2i(hexstr[20:22])
return res
def dec_psloci(hexstr):
res = {'p-tmsi': '', 'p-tmsi-sig': '', 'mcc': 0, 'mnc': 0, 'lac': '', 'rac': '', 'status': 0}
res['p-tmsi'] = hexstr[:8]
res['p-tmsi-sig'] = hexstr[8:14]
res['mcc'] = dec_mcc_from_plmn(hexstr[14:20])
res['mnc'] = dec_mnc_from_plmn(hexstr[14:20])
res['lac'] = hexstr[20:24]
res['rac'] = hexstr[24:26]
res['status'] = h2i(hexstr[26:28])
return res
def dec_epsloci(hexstr):
res = {'guti': '', 'mcc': 0, 'mnc': 0, 'tac': '', 'status': 0}
res['guti'] = hexstr[:24]
res['tai'] = hexstr[24:34]
res['mcc'] = dec_mcc_from_plmn(hexstr[24:30])
res['mnc'] = dec_mnc_from_plmn(hexstr[24:30])
res['tac'] = hexstr[30:34]
res['status'] = h2i(hexstr[34:36])
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'])
rec_str = "MCC: %3s MNC: %3s AcT: %s" % (rec_info['mcc'], rec_info['mnc'], ", ".join(rec_info['act']))
s += "\t%s # %s\n" % (rec_data, rec_str)
return s
@@ -255,317 +206,3 @@ def calculate_luhn(cc):
num = map(int, str(cc))
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
def mcc_from_imsi(imsi):
"""
Derive the MCC (Mobile Country Code) from the first three digits of an IMSI
"""
if imsi == None:
return None
if len(imsi) > 3:
return imsi[:3]
else:
return None
def mnc_from_imsi(imsi, long=False):
"""
Derive the MNC (Mobile Country Code) from the 4th to 6th digit of an IMSI
"""
if imsi == None:
return None
if len(imsi) > 3:
if long:
return imsi[3:6]
else:
return imsi[3:5]
else:
return None
def derive_mcc(digit1, digit2, digit3):
"""
Derive decimal representation of the MCC (Mobile Country Code)
from three given digits.
"""
mcc = 0
if digit1 != 0x0f:
mcc += digit1 * 100
if digit2 != 0x0f:
mcc += digit2 * 10
if digit3 != 0x0f:
mcc += digit3
return mcc
def derive_mnc(digit1, digit2, digit3=0x0f):
"""
Derive decimal representation of the MNC (Mobile Network Code)
from two or (optionally) three given digits.
"""
mnc = 0
# 3-rd digit is optional for the MNC. If present
# the algorythm is the same as for the MCC.
if digit3 != 0x0f:
return derive_mcc(digit1, digit2, digit3)
if digit1 != 0x0f:
mnc += digit1 * 10
if digit2 != 0x0f:
mnc += digit2
return mnc
def dec_msisdn(ef_msisdn):
"""
Decode MSISDN from EF.MSISDN or EF.ADN (same structure).
See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
"""
# Convert from str to (kind of) 'bytes'
ef_msisdn = h2b(ef_msisdn)
# Make sure mandatory fields are present
if len(ef_msisdn) < 14:
raise ValueError("EF.MSISDN is too short")
# Skip optional Alpha Identifier
xlen = len(ef_msisdn) - 14
msisdn_lhv = ef_msisdn[xlen:]
# Parse the length (in bytes) of the BCD encoded number
bcd_len = ord(msisdn_lhv[0])
# BCD length = length of dial num (max. 10 bytes) + 1 byte ToN and NPI
if bcd_len == 0xff:
return None
elif bcd_len > 11 or bcd_len < 1:
raise ValueError("Length of MSISDN (%d bytes) is out of range" % bcd_len)
# Parse ToN / NPI
ton = (ord(msisdn_lhv[1]) >> 4) & 0x07
npi = ord(msisdn_lhv[1]) & 0x0f
bcd_len -= 1
# No MSISDN?
if not bcd_len:
return (npi, ton, None)
msisdn = swap_nibbles(b2h(msisdn_lhv[2:][:bcd_len])).rstrip('f')
# International number 10.5.118/3GPP TS 24.008
if ton == 0x01:
msisdn = '+' + msisdn
return (npi, ton, msisdn)
def enc_msisdn(msisdn, npi=0x01, ton=0x03):
"""
Encode MSISDN as LHV so it can be stored to EF.MSISDN.
See 3GPP TS 31.102, section 4.2.26 and 4.4.2.3.
Default NPI / ToN values:
- NPI: ISDN / telephony numbering plan (E.164 / E.163),
- ToN: network specific or international number (if starts with '+').
"""
# Leading '+' indicates International Number
if msisdn[0] == '+':
msisdn = msisdn[1:]
ton = 0x01
# Append 'f' padding if number of digits is odd
if len(msisdn) % 2 > 0:
msisdn += 'f'
# BCD length also includes NPI/ToN header
bcd_len = len(msisdn) // 2 + 1
npi_ton = (npi & 0x0f) | ((ton & 0x07) << 4) | 0x80
bcd = rpad(swap_nibbles(msisdn), 10 * 2) # pad to 10 octets
return ('%02x' % bcd_len) + ('%02x' % npi_ton) + bcd
def dec_st(st, table="sim"):
"""
Parses the EF S/U/IST and prints the list of available services in EF S/U/IST
"""
if table == "isim":
from pySim.ts_31_103 import EF_IST_map
lookup_map = EF_IST_map
elif table == "usim":
from pySim.ts_31_102 import EF_UST_map
lookup_map = EF_UST_map
else:
from pySim.ts_51_011 import EF_SST_map
lookup_map = EF_SST_map
st_bytes = [st[i:i+2] for i in range(0, len(st), 2) ]
avail_st = ""
# Get each byte and check for available services
for i in range(0, len(st_bytes)):
# Byte i contains info about Services num (8i+1) to num (8i+8)
byte = int(st_bytes[i], 16)
# Services in each byte are in order MSB to LSB
# MSB - Service (8i+8)
# LSB - Service (8i+1)
for j in range(1, 9):
if byte&0x01 == 0x01 and ((8*i) + j in lookup_map):
# Byte X contains info about Services num (8X-7) to num (8X)
# bit = 1: service available
# bit = 0: service not available
avail_st += '\tService %d - %s\n' % ((8*i) + j, lookup_map[(8*i) + j])
byte = byte >> 1
return avail_st
def first_TLV_parser(bytelist):
'''
first_TLV_parser([0xAA, 0x02, 0xAB, 0xCD, 0xFF, 0x00]) -> (170, 2, [171, 205])
parses first TLV format record in a list of bytelist
returns a 3-Tuple: Tag, Length, Value
Value is a list of bytes
parsing of length is ETSI'style 101.220
'''
Tag = bytelist[0]
if bytelist[1] == 0xFF:
Len = bytelist[2]*256 + bytelist[3]
Val = bytelist[4:4+Len]
else:
Len = bytelist[1]
Val = bytelist[2:2+Len]
return (Tag, Len, Val)
def TLV_parser(bytelist):
'''
TLV_parser([0xAA, ..., 0xFF]) -> [(T, L, [V]), (T, L, [V]), ...]
loops on the input list of bytes with the "first_TLV_parser()" function
returns a list of 3-Tuples
'''
ret = []
while len(bytelist) > 0:
T, L, V = first_TLV_parser(bytelist)
if T == 0xFF:
# padding bytes
break
ret.append( (T, L, V) )
# need to manage length of L
if L > 0xFE:
bytelist = bytelist[ L+4 : ]
else:
bytelist = bytelist[ L+2 : ]
return ret
def dec_epdgid(hexstr):
"""
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.
"""
# Convert from hex str to int bytes list
epdgid_bytes = h2i(hexstr)
s = ""
# Get list of tuples containing parsed TLVs
tlvs = TLV_parser(epdgid_bytes)
for tlv in tlvs:
# tlv = (T, L, [V])
# T = Tag
# L = Length
# [V] = List of value
# Invalid Tag value scenario
if tlv[0] != 0x80:
continue
# Empty field - Zero length
if tlv[1] == 0:
continue
# First byte in the value has the address type
addr_type = tlv[2][0]
# TODO: Support parsing of IPv4 and IPv6
if addr_type == 0x00: #FQDN
# Skip address tye byte i.e. first byte in value list
content = tlv[2][1:]
s += "\t%s # %s\n" % (i2h(content), i2s(content))
return s
def enc_epdgid(epdg_addr, addr_type='00'):
"""
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.102 and 4.2.104.
Default values:
- addr_type: 00 - FQDN format of ePDG Address
"""
s = ""
# TODO: Encoding of IPv4 and IPv6 address
if addr_type == '00':
hex_str = s2h(epdg_addr)
s += '80' + ('%02x' % ((len(hex_str)//2)+1)) + '00' + hex_str
return s
def sanitize_pin_adm(opts):
"""
The ADM pin can be supplied either in its hexadecimal form or as
ascii string. This function checks the supplied opts parameter and
returns the pin_adm as hex encoded string, regardles in which form
it was originally supplied by the user
"""
pin_adm = None
if opts.pin_adm is not None:
if len(opts.pin_adm) <= 8:
pin_adm = ''.join(['%02x'%(ord(x)) for x in opts.pin_adm])
pin_adm = rpad(pin_adm, 16)
else:
raise ValueError("PIN-ADM needs to be <=8 digits (ascii)")
if opts.pin_adm_hex is not None:
if len(opts.pin_adm_hex) == 16:
pin_adm = opts.pin_adm_hex
# Ensure that it's hex-encoded
try:
try_encode = h2b(pin_adm)
except ValueError:
raise ValueError("PIN-ADM needs to be hex encoded using this option")
else:
raise ValueError("PIN-ADM needs to be exactly 16 digits (hex encoded)")
return pin_adm
def init_reader(opts):
"""
Init card reader driver
"""
if opts.pcsc_dev is not None:
print("Using PC/SC reader interface")
from pySim.transport.pcsc import PcscSimLink
sl = PcscSimLink(opts.pcsc_dev)
elif opts.osmocon_sock is not None:
print("Using Calypso-based (OsmocomBB) reader interface")
from pySim.transport.calypso import CalypsoSimLink
sl = CalypsoSimLink(sock_path=opts.osmocon_sock)
elif opts.modem_dev is not None:
print("Using modem for Generic SIM Access (3GPP TS 27.007)")
from pySim.transport.modem_atcmd import ModemATCommandLink
sl = ModemATCommandLink(device=opts.modem_dev, baudrate=opts.modem_baud)
else: # Serial reader is default
print("Using serial reader interface")
from pySim.transport.serial import SerialSimLink
sl = SerialSimLink(device=opts.device, baudrate=opts.baudrate)
return sl

View File

@@ -1,5 +0,0 @@
MCC=001
MNC=01
IMSI=001010000000111
ADM_HEX=CAE743DB9C5B5A58

View File

@@ -1,119 +0,0 @@
Using PC/SC reader interface
Reading ...
Autodetected card type: Fairwaves-SIM
ICCID: 8988219000000117833
IMSI: 001010000000111
GID1: ffffffffffffffff
GID2: ffffffffffffffff
SMSP: e1ffffffffffffffffffffffff0581005155f5ffffffffffff000000ffffffffffffffffffffffffffff
SPN: Fairwaves
Display HPLMN: False
Display OPLMN: False
PLMNsel: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNwAcT:
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
OPLMNwAcT:
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
HPLMNAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ACC: 0008
MSISDN: Not available
AD: 00000002
SIM Service Table: ff3cc3ff030fff0f000fff03f0c0
Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN)
Service 3 - Fixed Dialling Numbers (FDN)
Service 4 - Short Message Storage (SMS)
Service 5 - Advice of Charge (AoC)
Service 6 - Capability Configuration Parameters (CCP)
Service 7 - PLMN selector
Service 8 - RFU
Service 11 - Extension2
Service 12 - SMS Parameters
Service 13 - Last Number Dialled (LND)
Service 14 - Cell Broadcast Message Identifier
Service 17 - Service Provider Name
Service 18 - Service Dialling Numbers (SDN)
Service 23 - enhanced Multi-Level Precedence and Pre-emption Service
Service 24 - Automatic Answer for eMLPP
Service 25 - Data download via SMS-CB
Service 26 - Data download via SMS-PP
Service 27 - Menu selection
Service 28 - Call control
Service 29 - Proactive SIM
Service 30 - Cell Broadcast Message Identifier Ranges
Service 31 - Barred Dialling Numbers (BDN)
Service 32 - Extension4
Service 33 - De-personalization Control Keys
Service 34 - Co-operative Network List
Service 41 - USSD string data object supported in Call Control
Service 42 - RUN AT COMMAND command
Service 43 - User controlled PLMN Selector with Access Technology
Service 44 - Operator controlled PLMN Selector with Access Technology
Service 49 - MExE
Service 50 - Reserved and shall be ignored
Service 51 - PLMN Network Name
Service 52 - Operator PLMN List
Service 53 - Mailbox Dialling Numbers
Service 54 - Message Waiting Indication Status
Service 55 - Call Forwarding Indication Status
Service 56 - Service Provider Display Information
Service 57 - Multimedia Messaging Service (MMS)
Service 58 - Extension 8
Service 59 - MMS User Connectivity Parameters
USIM Service Table: 01ea1ffc21360480010000
Service 1 - Local Phone Book
Service 10 - Short Message Storage (SMS)
Service 12 - Short Message Service Parameters (SMSP)
Service 14 - Capability Configuration Parameters 2 (CCP2)
Service 15 - Cell Broadcast Message Identifier
Service 16 - Cell Broadcast Message Identifier Ranges
Service 17 - Group Identifier Level 1
Service 18 - Group Identifier Level 2
Service 19 - Service Provider Name
Service 20 - User controlled PLMN selector with Access Technology
Service 21 - MSISDN
Service 27 - GSM Access
Service 28 - Data download via SMS-PP
Service 29 - Data download via SMS-CB
Service 30 - Call Control by USIM
Service 31 - MO-SMS Control by USIM
Service 32 - RUN AT COMMAND command
Service 33 - shall be set to 1
Service 38 - GSM security context
Service 42 - Operator controlled PLMN selector with Access Technology
Service 43 - HPLMN selector with Access Technology
Service 45 - PLMN Network Name
Service 46 - Operator PLMN List
Service 51 - Service Provider Display Information
Service 64 - VGCS security
Service 65 - VBS security
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
Done !

View File

@@ -1,5 +0,0 @@
MCC=001
MNC=01
IMSI=001010000000102
ADM_HEX=15E31383624FDC8A

View File

@@ -1,135 +0,0 @@
Using PC/SC reader interface
Reading ...
Autodetected card type: Wavemobile-SIM
ICCID: 89445310150011013678
IMSI: 001010000000102
GID1: Can't read file -- SW match failed! Expected 9000 and got 6a82.
GID2: Can't read file -- SW match failed! Expected 9000 and got 6a82.
SMSP: e1ffffffffffffffffffffffff0581005155f5ffffffffffff000000ffffffffffffffffffffffffffff
SPN: wavemobile
Display HPLMN: False
Display OPLMN: False
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNwAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
OPLMNwAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 6a82.
ACC: abce
MSISDN: Not available
AD: 00ffff02
SIM Service Table: ff33ff0f3c00ff0f000cf0c0f0030000
Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN)
Service 3 - Fixed Dialling Numbers (FDN)
Service 4 - Short Message Storage (SMS)
Service 5 - Advice of Charge (AoC)
Service 6 - Capability Configuration Parameters (CCP)
Service 7 - PLMN selector
Service 8 - RFU
Service 9 - MSISDN
Service 10 - Extension1
Service 13 - Last Number Dialled (LND)
Service 14 - Cell Broadcast Message Identifier
Service 17 - Service Provider Name
Service 18 - Service Dialling Numbers (SDN)
Service 19 - Extension3
Service 20 - RFU
Service 21 - VGCS Group Identifier List (EFVGCS and EFVGCSS)
Service 22 - VBS Group Identifier List (EFVBS and EFVBSS)
Service 23 - enhanced Multi-Level Precedence and Pre-emption Service
Service 24 - Automatic Answer for eMLPP
Service 25 - Data download via SMS-CB
Service 26 - Data download via SMS-PP
Service 27 - Menu selection
Service 28 - Call control
Service 35 - Short Message Status Reports
Service 36 - Network's indication of alerting in the MS
Service 37 - Mobile Originated Short Message control by SIM
Service 38 - GPRS
Service 49 - MExE
Service 50 - Reserved and shall be ignored
Service 51 - PLMN Network Name
Service 52 - Operator PLMN List
Service 53 - Mailbox Dialling Numbers
Service 54 - Message Waiting Indication Status
Service 55 - Call Forwarding Indication Status
Service 56 - Service Provider Display Information
Service 57 - Multimedia Messaging Service (MMS)
Service 58 - Extension 8
Service 59 - MMS User Connectivity Parameters
USIM Service Table: 9eff1b3c37fe5900000000
Service 2 - Fixed Dialling Numbers (FDN)
Service 3 - Extension 2
Service 4 - Service Dialling Numbers (SDN)
Service 5 - Extension3
Service 8 - Outgoing Call Information (OCI and OCT)
Service 9 - Incoming Call Information (ICI and ICT)
Service 10 - Short Message Storage (SMS)
Service 11 - Short Message Status Reports (SMSR)
Service 12 - Short Message Service Parameters (SMSP)
Service 13 - Advice of Charge (AoC)
Service 14 - Capability Configuration Parameters 2 (CCP2)
Service 15 - Cell Broadcast Message Identifier
Service 16 - Cell Broadcast Message Identifier Ranges
Service 17 - Group Identifier Level 1
Service 18 - Group Identifier Level 2
Service 20 - User controlled PLMN selector with Access Technology
Service 21 - MSISDN
Service 27 - GSM Access
Service 28 - Data download via SMS-PP
Service 29 - Data download via SMS-CB
Service 30 - Call Control by USIM
Service 33 - shall be set to 1
Service 34 - Enabled Services Table
Service 35 - APN Control List (ACL)
Service 37 - Co-operative Network List
Service 38 - GSM security context
Service 42 - Operator controlled PLMN selector with Access Technology
Service 43 - HPLMN selector with Access Technology
Service 44 - Extension 5
Service 45 - PLMN Network Name
Service 46 - Operator PLMN List
Service 47 - Mailbox Dialling Numbers
Service 48 - Message Waiting Indication Status
Service 49 - Call Forwarding Indication Status
Service 52 - Multimedia Messaging Service (MMS)
Service 53 - Extension 8
Service 55 - MMS User Connectivity Parameters
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
Done !

View File

@@ -1,57 +1,14 @@
Using PC/SC reader interface
Using PC/SC reader (dev=1) interface
Reading ...
Autodetected card type: fakemagicsim
Can't read AIDs from SIM -- SW match failed! Expected 9000 and got 9404.
ICCID: 1122334455667788990
IMSI: 001010000000102
GID1: Can't read file -- SW match failed! Expected 9000 and got 9404.
GID2: Can't read file -- SW match failed! Expected 9000 and got 9404.
SMSP: ffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
SPN: Magic
Display HPLMN: True
Display OPLMN: False
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNsel: fff11fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
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.
ACC: ffff
MSISDN: Not available
AD: 000000
SIM Service Table: ff3fff0f0300f003000c
Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN)
Service 3 - Fixed Dialling Numbers (FDN)
Service 4 - Short Message Storage (SMS)
Service 5 - Advice of Charge (AoC)
Service 6 - Capability Configuration Parameters (CCP)
Service 7 - PLMN selector
Service 8 - RFU
Service 9 - MSISDN
Service 10 - Extension1
Service 11 - Extension2
Service 12 - SMS Parameters
Service 13 - Last Number Dialled (LND)
Service 14 - Cell Broadcast Message Identifier
Service 17 - Service Provider Name
Service 18 - Service Dialling Numbers (SDN)
Service 19 - Extension3
Service 20 - RFU
Service 21 - VGCS Group Identifier List (EFVGCS and EFVGCSS)
Service 22 - VBS Group Identifier List (EFVBS and EFVBSS)
Service 23 - enhanced Multi-Level Precedence and Pre-emption Service
Service 24 - Automatic Answer for eMLPP
Service 25 - Data download via SMS-CB
Service 26 - Data download via SMS-PP
Service 27 - Menu selection
Service 28 - Call control
Service 33 - De-personalization Control Keys
Service 34 - Co-operative Network List
Service 53 - Mailbox Dialling Numbers
Service 54 - Message Waiting Indication Status
Service 55 - Call Forwarding Indication Status
Service 56 - Service Provider Display Information
Service 57 - Multimedia Messaging Service (MMS)
Service 58 - Extension 8
Done !

View File

@@ -1,7 +0,0 @@
MCC=001
MNC=01
ICCID=1122334455667788990
KI=AABBCCDDEEFFAABBCCDDEEFFAABBCCDD
OPC=12345678901234567890123456789012
IMSI=001010000000102
ADM=72273953

View File

@@ -1,169 +0,0 @@
Using PC/SC reader interface
Reading ...
Autodetected card type: sysmoISIM-SJA2
ICCID: 8988211900000000004
IMSI: 001010000000102
GID1: ffffffffffffffffffff
GID2: ffffffffffffffffffff
SMSP: ffffffffffffffffffffffffffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
SPN: Not available
Display HPLMN: False
Display OPLMN: False
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNwAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
OPLMNwAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
HPLMNAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ACC: 0001
MSISDN (NPI=1 ToN=1): +1234
AD: 00000002
SIM Service Table: ff33ffff3f003f0f300cf0c3f00000
Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN)
Service 3 - Fixed Dialling Numbers (FDN)
Service 4 - Short Message Storage (SMS)
Service 5 - Advice of Charge (AoC)
Service 6 - Capability Configuration Parameters (CCP)
Service 7 - PLMN selector
Service 8 - RFU
Service 9 - MSISDN
Service 10 - Extension1
Service 13 - Last Number Dialled (LND)
Service 14 - Cell Broadcast Message Identifier
Service 17 - Service Provider Name
Service 18 - Service Dialling Numbers (SDN)
Service 19 - Extension3
Service 20 - RFU
Service 21 - VGCS Group Identifier List (EFVGCS and EFVGCSS)
Service 22 - VBS Group Identifier List (EFVBS and EFVBSS)
Service 23 - enhanced Multi-Level Precedence and Pre-emption Service
Service 24 - Automatic Answer for eMLPP
Service 25 - Data download via SMS-CB
Service 26 - Data download via SMS-PP
Service 27 - Menu selection
Service 28 - Call control
Service 29 - Proactive SIM
Service 30 - Cell Broadcast Message Identifier Ranges
Service 31 - Barred Dialling Numbers (BDN)
Service 32 - Extension4
Service 33 - De-personalization Control Keys
Service 34 - Co-operative Network List
Service 35 - Short Message Status Reports
Service 36 - Network's indication of alerting in the MS
Service 37 - Mobile Originated Short Message control by SIM
Service 38 - GPRS
Service 49 - MExE
Service 50 - Reserved and shall be ignored
Service 51 - PLMN Network Name
Service 52 - Operator PLMN List
Service 53 - Mailbox Dialling Numbers
Service 54 - Message Waiting Indication Status
Service 57 - Multimedia Messaging Service (MMS)
Service 58 - Extension 8
Service 59 - MMS User Connectivity Parameters
EHPLMN:
00f110 # MCC: 001 MNC: 001
ffffff # unused
ffffff # unused
ffffff # unused
USIM Service Table: beff9f9de73e0408400170730000002e00000000
Service 2 - Fixed Dialling Numbers (FDN)
Service 3 - Extension 2
Service 4 - Service Dialling Numbers (SDN)
Service 5 - Extension3
Service 6 - Barred Dialling Numbers (BDN)
Service 8 - Outgoing Call Information (OCI and OCT)
Service 9 - Incoming Call Information (ICI and ICT)
Service 10 - Short Message Storage (SMS)
Service 11 - Short Message Status Reports (SMSR)
Service 12 - Short Message Service Parameters (SMSP)
Service 13 - Advice of Charge (AoC)
Service 14 - Capability Configuration Parameters 2 (CCP2)
Service 15 - Cell Broadcast Message Identifier
Service 16 - Cell Broadcast Message Identifier Ranges
Service 17 - Group Identifier Level 1
Service 18 - Group Identifier Level 2
Service 19 - Service Provider Name
Service 20 - User controlled PLMN selector with Access Technology
Service 21 - MSISDN
Service 24 - Enhanced Multi-Level Precedence and Pre-emption Service
Service 25 - Automatic Answer for eMLPP
Service 27 - GSM Access
Service 28 - Data download via SMS-PP
Service 29 - Data download via SMS-CB
Service 32 - RUN AT COMMAND command
Service 33 - shall be set to 1
Service 34 - Enabled Services Table
Service 35 - APN Control List (ACL)
Service 38 - GSM security context
Service 39 - CPBCCH Information
Service 40 - Investigation Scan
Service 42 - Operator controlled PLMN selector with Access Technology
Service 43 - HPLMN selector with Access Technology
Service 44 - Extension 5
Service 45 - PLMN Network Name
Service 46 - Operator PLMN List
Service 51 - Service Provider Display Information
Service 60 - User Controlled PLMN selector for I-WLAN access
Service 71 - Equivalent HPLMN
Service 73 - Equivalent HPLMN Presentation Indication
Service 85 - EPS Mobility Management Information
Service 86 - Allowed CSG Lists and corresponding indications
Service 87 - Call control on EPS PDN connection by USIM
Service 89 - eCall Data
Service 90 - Operator CSG Lists and corresponding indications
Service 93 - Communication Control for IMS by USIM
Service 94 - Extended Terminal Applications
Service 95 - Support of UICC access to IMS
ePDGId:
Not available
ISIM Service Table: 190200
Service 1 - P-CSCF address
Service 4 - GBA-based Local Key Establishment Mechanism
Service 5 - Support of P-CSCF discovery for IMS Local Break Out
Service 10 - Support of UICC access to IMS
Done !

View File

@@ -4,5 +4,4 @@ ICCID=1122334455667788990
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
IMSI=001010000000102
MSISDN=+77776336143
ADM=55538407

View File

@@ -1,17 +1,11 @@
Using PC/SC reader interface
Using PC/SC reader (dev=0) interface
Reading ...
Autodetected card type: sysmoUSIM-SJS1
ICCID: 1122334455667788990
IMSI: 001010000000102
GID1: ffffffffffffffffffff
GID2: ffffffffffffffffffff
SMSP: ffffffffffffffffffffffffffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
SPN: Magic
Display HPLMN: True
Display OPLMN: True
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNsel: fff11fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNwAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
fff11fffff # MCC: 1651 MNC: 151 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
@@ -25,7 +19,7 @@ PLMNwAcT:
ffffff0000 # unused
OPLMNwAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
fff11fffff # MCC: 1651 MNC: 151 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
@@ -39,105 +33,21 @@ OPLMNwAcT:
ffffff0000 # unused
HPLMNAcT:
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffff0000 # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ffffffffff # unused
ACC: 0008
MSISDN (NPI=1 ToN=1): +77776336143
MSISDN: Not available
AD: 00000002
SIM Service Table: ff3fffff3f003f1ff00c00c0f00000
Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN)
Service 3 - Fixed Dialling Numbers (FDN)
Service 4 - Short Message Storage (SMS)
Service 5 - Advice of Charge (AoC)
Service 6 - Capability Configuration Parameters (CCP)
Service 7 - PLMN selector
Service 8 - RFU
Service 9 - MSISDN
Service 10 - Extension1
Service 11 - Extension2
Service 12 - SMS Parameters
Service 13 - Last Number Dialled (LND)
Service 14 - Cell Broadcast Message Identifier
Service 17 - Service Provider Name
Service 18 - Service Dialling Numbers (SDN)
Service 19 - Extension3
Service 20 - RFU
Service 21 - VGCS Group Identifier List (EFVGCS and EFVGCSS)
Service 22 - VBS Group Identifier List (EFVBS and EFVBSS)
Service 23 - enhanced Multi-Level Precedence and Pre-emption Service
Service 24 - Automatic Answer for eMLPP
Service 25 - Data download via SMS-CB
Service 26 - Data download via SMS-PP
Service 27 - Menu selection
Service 28 - Call control
Service 29 - Proactive SIM
Service 30 - Cell Broadcast Message Identifier Ranges
Service 31 - Barred Dialling Numbers (BDN)
Service 32 - Extension4
Service 33 - De-personalization Control Keys
Service 34 - Co-operative Network List
Service 35 - Short Message Status Reports
Service 36 - Network's indication of alerting in the MS
Service 37 - Mobile Originated Short Message control by SIM
Service 38 - GPRS
Service 49 - MExE
Service 50 - Reserved and shall be ignored
Service 51 - PLMN Network Name
Service 52 - Operator PLMN List
Service 53 - Mailbox Dialling Numbers
Service 54 - Message Waiting Indication Status
Service 57 - Multimedia Messaging Service (MMS)
Service 58 - Extension 8
Service 59 - MMS User Connectivity Parameters
USIM Service Table: 9e6b1dfc67f6580000
Service 2 - Fixed Dialling Numbers (FDN)
Service 3 - Extension 2
Service 4 - Service Dialling Numbers (SDN)
Service 5 - Extension3
Service 8 - Outgoing Call Information (OCI and OCT)
Service 9 - Incoming Call Information (ICI and ICT)
Service 10 - Short Message Storage (SMS)
Service 12 - Short Message Service Parameters (SMSP)
Service 14 - Capability Configuration Parameters 2 (CCP2)
Service 15 - Cell Broadcast Message Identifier
Service 17 - Group Identifier Level 1
Service 19 - Service Provider Name
Service 20 - User controlled PLMN selector with Access Technology
Service 21 - MSISDN
Service 27 - GSM Access
Service 28 - Data download via SMS-PP
Service 29 - Data download via SMS-CB
Service 30 - Call Control by USIM
Service 31 - MO-SMS Control by USIM
Service 32 - RUN AT COMMAND command
Service 33 - shall be set to 1
Service 34 - Enabled Services Table
Service 35 - APN Control List (ACL)
Service 38 - GSM security context
Service 39 - CPBCCH Information
Service 42 - Operator controlled PLMN selector with Access Technology
Service 43 - HPLMN selector with Access Technology
Service 45 - PLMN Network Name
Service 46 - Operator PLMN List
Service 47 - Mailbox Dialling Numbers
Service 48 - Message Waiting Indication Status
Service 52 - Multimedia Messaging Service (MMS)
Service 53 - Extension 8
Service 55 - MMS User Connectivity Parameters
ePDGId: Can't read file -- SW match failed! Expected 9000 and got 6a82.
Done !

View File

@@ -1,55 +1,14 @@
Using PC/SC reader interface
Using PC/SC reader (dev=2) interface
Reading ...
Autodetected card type: sysmosim-gr1
Can't read AIDs from SIM -- SW match failed! Expected 9000 and got 9404.
ICCID: 1122334455667788990
IMSI: 001010000000102
GID1: Can't read file -- SW match failed! Expected 9000 and got 9404.
GID2: Can't read file -- SW match failed! Expected 9000 and got 9404.
SMSP: ffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
SPN: Not available
Display HPLMN: False
Display OPLMN: False
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNsel: fff11fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
PLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
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.
ACC: 0008
MSISDN: Not available
AD: 000000
SIM Service Table: ff3fff0f0f0000030000
Service 1 - CHV1 disable function
Service 2 - Abbreviated Dialling Numbers (ADN)
Service 3 - Fixed Dialling Numbers (FDN)
Service 4 - Short Message Storage (SMS)
Service 5 - Advice of Charge (AoC)
Service 6 - Capability Configuration Parameters (CCP)
Service 7 - PLMN selector
Service 8 - RFU
Service 9 - MSISDN
Service 10 - Extension1
Service 11 - Extension2
Service 12 - SMS Parameters
Service 13 - Last Number Dialled (LND)
Service 14 - Cell Broadcast Message Identifier
Service 17 - Service Provider Name
Service 18 - Service Dialling Numbers (SDN)
Service 19 - Extension3
Service 20 - RFU
Service 21 - VGCS Group Identifier List (EFVGCS and EFVGCSS)
Service 22 - VBS Group Identifier List (EFVBS and EFVBSS)
Service 23 - enhanced Multi-Level Precedence and Pre-emption Service
Service 24 - Automatic Answer for eMLPP
Service 25 - Data download via SMS-CB
Service 26 - Data download via SMS-PP
Service 27 - Menu selection
Service 28 - Call control
Service 33 - De-personalization Control Keys
Service 34 - Co-operative Network List
Service 35 - Short Message Status Reports
Service 36 - Network's indication of alerting in the MS
Service 57 - Multimedia Messaging Service (MMS)
Service 58 - Extension 8
Done !

View File

@@ -1,13 +0,0 @@
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)

View File

@@ -1,5 +1,5 @@
MCC=001
MNC=01
IMSI=001010000000102
ADM_HEX=0123456789ABCDEF
ADM=0123456789ABCDEF

View File

@@ -91,7 +91,6 @@ function check_card {
echo "------------8<------------"
cat $TEMPFILE
echo "------------8<------------"
rm *.tmp
exit 1
fi
@@ -156,17 +155,10 @@ function run_test {
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
IMSI=001010000000001
MSISDN=6766266
ADM=00000000
ADM_HEX=""
ADM_OPT="-a"
source "$CARD_NAME.data"
if [ -n "$ADM_HEX" ]; then
ADM_OPT="-A"
ADM=$ADM_HEX
fi
python $PYSIM_PROG -p $I -t $CARD_NAME -o $OPC -k $KI -x $MCC -y $MNC -i $IMSI -s $ICCID --msisdn $MSISDN $ADM_OPT $ADM
. "$CARD_NAME.data"
python $PYSIM_PROG -p $I -t $CARD_NAME -o $OPC -k $KI -x $MCC -y $MNC -i $IMSI -s $ICCID -a $ADM
check_card $I $CARD_NAME
echo ""
done

View File

@@ -4,5 +4,4 @@ ICCID=1122334455667788990
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
IMSI=001010000000102
MSISDN=+77776336143
ADM=12345678