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
31 changed files with 449 additions and 3207 deletions

View File

@@ -40,8 +40,8 @@ pysim requires:
Example for Debian:
apt-get install python3-pyscard python3-serial python3-pip python3-yaml
pip3 install pytlv
apt-get install python-pyscard python-serial python-pip
pip install pytlv
Mailing List
@@ -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

@@ -9,10 +9,9 @@ if [ ! -d "./pysim-testdata/" ] ; then
exit 1
fi
virtualenv -p python3 venv --system-site-packages
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,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python2
#
# Utility to deal with sim cards and program the 'magic' ones easily
@@ -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,25 +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("--epdgid", dest="epdgid",
help="Set Home Evolved Packet Data Gateway (ePDG) Identifier. (Only FQDN format supported)",
)
parser.add_option("--epdgSelection", dest="epdgSelection",
help="Set PLMN for ePDG Selection Information. (Only Operator Identifier FQDN format supported)",
)
parser.add_option("--pcscf", dest="pcscf",
help="Set Proxy Call Session Control Function (P-CSCF) Address. (Only FQDN format supported)",
)
parser.add_option("--ims-hdomain", dest="ims_hdomain",
help="Set IMS Home Network Domain Name in FQDN format",
)
parser.add_option("--impi", dest="impi",
help="Set IMS private user identity",
)
parser.add_option("--impu", dest="impu",
help="Set IMS public user identity",
)
)
parser.add_option("--read-imsi", dest="read_imsi", action="store_true",
help="Read the IMSI from the CARD", default=False
)
@@ -199,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):
@@ -240,13 +198,12 @@ def parse_options():
def _digits(secret, usage, len, num):
seed = secret + usage + '%d' % num
s = hashlib.sha1(seed.encode())
d = ''.join(['%02d' % x for x in s.digest()])
s = hashlib.sha1(secret + usage + '%d' % num)
d = ''.join(['%02d'%ord(x) for x in s.digest()])
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
@@ -276,7 +233,7 @@ def _dbi_binary_quote(s):
m = sum_
e = i
if m == 0: # No overhead ? use this !
break
break;
# Generate output
out = []
@@ -299,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)
@@ -317,26 +265,11 @@ 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
if not _isnum(iccid, 19) and not _isnum(iccid, 20):
raise ValueError('ICCID must be 19 or 20 digits !')
raise ValueError('ICCID must be 19 or 20 digits !');
else:
if opts.num is None:
@@ -345,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)
@@ -446,16 +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
# ePDG Selection Information
if opts.epdgSelection:
if len(opts.epdgSelection) < 5 or len(opts.epdgSelection) > 6:
raise ValueError('ePDG Selection Information is not valid')
epdg_mcc = opts.epdgSelection[:3]
epdg_mnc = opts.epdgSelection[3:]
if not epdg_mcc.isdigit() or not epdg_mnc.isdigit():
raise ValueError('PLMN for ePDG Selection must only contain decimal digits')
# Return that
return {
@@ -468,33 +402,23 @@ def gen_parameters(opts):
'ki' : ki,
'opc' : opc,
'acc' : acc,
'pin_adm' : pin_adm,
'msisdn' : opts.msisdn,
'epdgid' : opts.epdgid,
'epdgSelection' : opts.epdgSelection,
'pcscf' : opts.pcscf,
'ims_hdomain': opts.ims_hdomain,
'impi' : opts.impi,
'impu' : opts.impu,
'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):
@@ -511,26 +435,22 @@ 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:
f.close()
return row
return row;
i += 1
if row['iccid'] == iccid:
f.close()
return row
return row;
if row['imsi'] == imsi:
f.close()
return row
return row;
f.close()
return None
@@ -538,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
@@ -614,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 ...
@@ -622,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
@@ -645,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__':
@@ -719,58 +576,110 @@ if __name__ == '__main__':
opts = parse_options()
# Init card reader driver
sl = init_reader(opts)
if sl is None:
exit(1)
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

@@ -1,4 +1,4 @@
#!/usr/bin/env python3
#!/usr/bin/env python2
#
# Utility to display some informations about a SIM card
@@ -28,15 +28,17 @@ import os
import random
import re
import sys
from pySim.ts_51_011 import EF, DF, EF_SST_map, EF_AD_mode_map
from pySim.ts_31_102 import EF_UST_map, EF_USIM_ADF_map
from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map
from pySim.ts_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, UsimCard, IsimCard
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, dec_msisdn
from pySim.utils import format_xplmn_w_act, dec_spn, dec_st, init_reader, dec_addr_tlv
from pySim.utils import h2s, format_ePDGSelection
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, format_xplmn_w_act
def parse_options():
@@ -54,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,
@@ -81,9 +75,21 @@ if __name__ == '__main__':
opts = parse_options()
# Init card reader driver
sl = init_reader(opts)
if sl is None:
exit(1)
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)
@@ -91,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:
@@ -213,154 +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("Administrative data: %s" % (res,))
if res[:2] in EF_AD_mode_map:
print("\tMS operation mode: %s" % (EF_AD_mode_map[res[:2]],))
else:
print("\tMS operation mode: (unknown 0x%s)" % (res[:2],))
if int(res[4:6], 16) & 0x01:
print("\tCiphering Indicator: enabled")
else:
print("\tCiphering Indicator: disabled")
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():
# Select USIM profile
usim_card = UsimCard(scc)
# EF.EHPLMN
if usim_card.file_exists(EF_USIM_ADF_map['EHPLMN']):
(res, sw) = usim_card.read_ehplmn()
if sw == '9000':
print("EHPLMN:\n%s" % (res))
else:
print("EHPLMN: Can't read, response code = %s" % (sw,))
# EF.UST
try:
if usim_card.file_exists(EF_USIM_ADF_map['UST']):
# res[0] - EF content of UST
# res[1] - Human readable format of services marked available in UST
(res, sw) = usim_card.read_ust()
if sw == '9000':
print("USIM Service Table: %s" % res[0])
print("%s" % res[1])
else:
print("USIM Service Table: Can't read, response code = %s" % (sw,))
except Exception as e:
print("USIM Service Table: Can't read file -- " + str(e))
#EF.ePDGId - Home ePDG Identifier
try:
if usim_card.file_exists(EF_USIM_ADF_map['ePDGId']):
(res, sw) = usim_card.read_epdgid()
if sw == '9000':
print("ePDGId:\n%s" % (len(res) and res 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))
#EF.ePDGSelection - ePDG Selection Information
try:
if usim_card.file_exists(EF_USIM_ADF_map['ePDGSelection']):
(res, sw) = usim_card.read_ePDGSelection()
if sw == '9000':
print("ePDGSelection:\n%s" % (res,))
else:
print("ePDGSelection: Can't read, response code = %s" % (sw,))
except Exception as e:
print("ePDGSelection: Can't read file -- " + str(e))
# Select ISIM application by its AID
if '9000' == card.select_adf_by_aid(adf="isim"):
# Select USIM profile
isim_card = IsimCard(scc)
#EF.P-CSCF - P-CSCF Address
try:
if isim_card.file_exists(EF_ISIM_ADF_map['PCSCF']):
res = isim_card.read_pcscf()
print("P-CSCF:\n%s" % (len(res) and res or '\tNot available\n',))
except Exception as e:
print("P-CSCF: Can't read file -- " + str(e))
# EF.DOMAIN - Home Network Domain Name e.g. ims.mncXXX.mccXXX.3gppnetwork.org
try:
if isim_card.file_exists(EF_ISIM_ADF_map['DOMAIN']):
(res, sw) = isim_card.read_domain()
if sw == '9000':
print("Home Network Domain Name: %s" % (len(res) and res or 'Not available',))
else:
print("Home Network Domain Name: Can't read, response code = %s" % (sw,))
except Exception as e:
print("Home Network Domain Name: Can't read file -- " + str(e))
# EF.IMPI - IMS private user identity
try:
if isim_card.file_exists(EF_ISIM_ADF_map['IMPI']):
(res, sw) = isim_card.read_impi()
if sw == '9000':
print("IMS private user identity: %s" % (len(res) and res or 'Not available',))
else:
print("IMS private user identity: Can't read, response code = %s" % (sw,))
except Exception as e:
print("IMS private user identity: Can't read file -- " + str(e))
# EF.IMPU - IMS public user identity
try:
if isim_card.file_exists(EF_ISIM_ADF_map['IMPU']):
res = isim_card.read_impu()
print("IMS public user identity:\n%s" % (len(res) and res or '\tNot available\n',))
except Exception as e:
print("IMS public user identity: Can't read file -- " + str(e))
# EF.UICCIARI - UICC IARI
try:
if isim_card.file_exists(EF_ISIM_ADF_map['UICCIARI']):
res = isim_card.read_iari()
print("UICC IARI:\n%s" % (len(res) and res or '\tNot available\n',))
except Exception as e:
print("UICC IARI: Can't read file -- " + str(e))
# Check whether we have th AID of ISIM, if so select it by its AID
# 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 python3
# -*- 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,33 +24,18 @@
#
from pySim.ts_51_011 import EF, DF
from pySim.ts_31_102 import EF_USIM_ADF_map
from pySim.ts_31_103 import EF_ISIM_ADF_map
from pySim.utils import *
from smartcard.util import toBytes
from pytlv.TLV import *
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
@@ -80,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
@@ -98,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
@@ -155,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
@@ -184,259 +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)
# 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
def read_epdgid(self):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
if sw == '9000':
return (dec_addr_tlv(res), sw)
else:
return (None, sw)
def update_epdgid(self, epdgid):
size = self._scc.binary_size(EF_USIM_ADF_map['ePDGId']) * 2
if len(epdgid) > 0:
addr_type = get_addr_type(epdgid)
if addr_type == None:
raise ValueError("Unknown ePDG Id address type or invalid address provided")
epdgid_tlv = rpad(enc_addr_tlv(epdgid, ('%02x' % addr_type)), size)
else:
epdgid_tlv = rpad('ff', size)
data, sw = self._scc.update_binary(
EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
return sw
def read_ePDGSelection(self):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'])
if sw == '9000':
return (format_ePDGSelection(res), sw)
else:
return (None, sw)
def update_ePDGSelection(self, mcc, mnc):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'], length=None, offset=0)
if sw == '9000' and (len(mcc) == 0 or len(mnc) == 0):
# Reset contents
# 80 - Tag value
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['ePDGSelection'], rpad('', len(res)))
elif sw == '9000':
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['ePDGSelection'], enc_ePDGSelection(res, mcc, mnc))
return sw
def read_ust(self):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
if sw == '9000':
# Print those which are available
return ([res, dec_st(res, table="usim")], sw)
else:
return ([None, None], sw)
def update_ust(self, service, bit=1):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
if sw == '9000':
content = enc_st(res, service, bit)
(res, sw) = self._scc.update_binary(EF_USIM_ADF_map['UST'], content)
return sw
class IsimCard(Card):
def __init__(self, ssc):
super(IsimCard, self).__init__(ssc)
def read_pcscf(self):
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['PCSCF'])
pcscf_recs = ""
for i in range(0, rec_cnt):
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['PCSCF'], i + 1)
if sw == '9000':
content = dec_addr_tlv(res)
pcscf_recs += "%s" % (len(content) and content or '\tNot available\n')
else:
pcscf_recs += "\tP-CSCF: Can't read, response code = %s\n" % (sw)
return pcscf_recs
def update_pcscf(self, pcscf):
if len(pcscf) > 0:
addr_type = get_addr_type(pcscf)
if addr_type == None:
raise ValueError("Unknown PCSCF address type or invalid address provided")
content = enc_addr_tlv(pcscf, ('%02x' % addr_type))
else:
# Just the tag value
content = '80'
rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['PCSCF'])
pcscf_tlv = rpad(content, rec_size_bytes*2)
data, sw = self._scc.update_record(EF_ISIM_ADF_map['PCSCF'], 1, pcscf_tlv)
return sw
def read_domain(self):
(res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['DOMAIN'])
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
return (content, sw)
else:
return (None, sw)
def update_domain(self, domain=None, mcc=None, mnc=None):
hex_str = ""
if domain:
hex_str = s2h(domain)
elif mcc and mnc:
# MCC and MNC always has 3 digits in domain form
plmn_str = 'mnc' + lpad(mnc, 3, "0") + '.mcc' + lpad(mcc, 3, "0")
hex_str = s2h('ims.' + plmn_str + '.3gppnetwork.org')
# Build TLV
tlv = TLV(['80'])
content = tlv.build({'80': hex_str})
bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['DOMAIN'])
data, sw = self._scc.update_binary(EF_ISIM_ADF_map['DOMAIN'], rpad(content, bin_size_bytes*2))
return sw
def read_impi(self):
(res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IMPI'])
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
return (content, sw)
else:
return (None, sw)
def update_impi(self, impi=None):
hex_str = ""
if impi:
hex_str = s2h(impi)
# Build TLV
tlv = TLV(['80'])
content = tlv.build({'80': hex_str})
bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['IMPI'])
data, sw = self._scc.update_binary(EF_ISIM_ADF_map['IMPI'], rpad(content, bin_size_bytes*2))
return sw
def read_impu(self):
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['IMPU'])
impu_recs = ""
for i in range(0, rec_cnt):
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['IMPU'], i + 1)
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
impu_recs += "\t%s\n" % (len(content) and content or 'Not available')
else:
impu_recs += "IMS public user identity: Can't read, response code = %s\n" % (sw)
return impu_recs
def update_impu(self, impu=None):
hex_str = ""
if impu:
hex_str = s2h(impu)
# Build TLV
tlv = TLV(['80'])
content = tlv.build({'80': hex_str})
rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['IMPU'])
impu_tlv = rpad(content, rec_size_bytes*2)
data, sw = self._scc.update_record(EF_ISIM_ADF_map['IMPU'], 1, impu_tlv)
return sw
def read_iari(self):
rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['UICCIARI'])
uiari_recs = ""
for i in range(0, rec_cnt):
(res, sw) = self._scc.read_record(EF_ISIM_ADF_map['UICCIARI'], i + 1)
if sw == '9000':
# Skip the inital tag value ('80') byte and get length of contents
length = int(res[2:4], 16)
content = h2s(res[4:4+(length*2)])
uiari_recs += "\t%s\n" % (len(content) and content or 'Not available')
else:
uiari_recs += "UICC IARI: Can't read, response code = %s\n" % (sw)
return uiari_recs
class _MagicSimBase(Card):
"""
@@ -444,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
@@ -481,7 +188,7 @@ class _MagicSimBase(Card):
r = self._scc.select_file(['3f00', '7f4d', f[0]])
rec_len = int(r[-1][28:30], 16)
tlen = int(r[-1][4:8],16)
rec_cnt = (tlen / rec_len) - 1
rec_cnt = (tlen / rec_len) - 1;
if (rec_cnt < 1) or (rec_len != f[1]):
raise RuntimeError('Bad card type')
@@ -611,7 +318,7 @@ class FakeMagicSim(Card):
r = self._scc.select_file(['3f00', '000c'])
rec_len = int(r[-1][28:30], 16)
tlen = int(r[-1][4:8],16)
rec_cnt = (tlen / rec_len) - 1
rec_cnt = (tlen / rec_len) - 1;
if (rec_cnt < 1) or (rec_len != 0x5a):
raise RuntimeError('Bad card type')
@@ -668,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)
@@ -687,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))
@@ -708,6 +415,8 @@ class GrcardSim(Card):
# FIXME: EF.MSISDN
def erase(self):
return
class SysmoSIMgr1(GrcardSim):
"""
@@ -717,7 +426,7 @@ class SysmoSIMgr1(GrcardSim):
"""
name = 'sysmosim-gr1'
@classmethod
@classmethod
def autodetect(kls, scc):
try:
# Look for ATR
@@ -727,7 +436,7 @@ class SysmoSIMgr1(GrcardSim):
return None
return None
class SysmoUSIMgr1(UsimCard):
class SysmoUSIMgr1(Card):
"""
sysmocom sysmoUSIM-GR1
"""
@@ -752,6 +461,9 @@ class SysmoUSIMgr1(UsimCard):
)
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
def erase(self):
return
class SysmoSIMgr2(Card):
"""
@@ -772,9 +484,9 @@ class SysmoSIMgr2(Card):
def program(self, p):
# select MF
# select MF
r = self._scc.select_file(['3f00'])
# authenticate as SUPER ADM using default key
self._scc.verify_chv(0x0b, h2b("3838383838383838"))
@@ -783,14 +495,14 @@ 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")
pdu = 'A0D43A0508' + b2h(pin)
data, sw = self._scc._tp.send_apdu(pdu)
# authenticate as ADM (enough to write file, and can set PINs)
self._scc.verify_chv(0x05, pin)
@@ -800,7 +512,7 @@ class SysmoSIMgr2(Card):
# select DF_GSM
r = self._scc.select_file(['7f20'])
# write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
@@ -822,13 +534,15 @@ class SysmoSIMgr2(Card):
# select DF_TELECOM
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
"""
@@ -853,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'])
@@ -874,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)
@@ -920,19 +620,11 @@ 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(UsimCard):
class FairwavesSIM(Card):
"""
FairwavesSIM
@@ -944,7 +636,7 @@ class FairwavesSIM(UsimCard):
3F00/7F20/FF02: Ki
"""
name = 'Fairwaves-SIM'
name = 'Fairwaves SIM'
# Propriatary files
_EF_num = {
'Ki': 'FF02',
@@ -1072,13 +764,17 @@ class FairwavesSIM(UsimCard):
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)
@@ -1121,7 +817,7 @@ class OpenCellsSim(Card):
# write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
class WavemobileSim(UsimCard):
class WavemobileSim(Card):
"""
WavemobileSim
@@ -1152,28 +848,28 @@ class WavemobileSim(UsimCard):
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':
@@ -1186,260 +882,39 @@ class WavemobileSim(UsimCard):
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
class SysmoISIMSJA2(UsimCard, IsimCard):
"""
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)
# EF.MSISDN
# TODO: Alpha Identifier (currently 'ff'O * 20)
# TODO: Capability/Configuration1 Record Identifier
# TODO: Extension1 Record Identifier
if p.get('msisdn') is not None:
msisdn = enc_msisdn(p['msisdn'])
content = 'ff' * 20 + msisdn + 'ff' * 2
r = self._scc.select_file(['3f00', '7f10'])
data, sw = self._scc.update_record('6F40', 1, content, force_len=True)
# EF.ACC
if p.get('acc'):
sw = self.update_acc(p['acc'])
if sw != '9000':
print("Programming ACC failed with code %s"%sw)
# Populate AIDs
self.read_aids()
# update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
# 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
if '9000' == self.select_adf_by_aid(adf="isim"):
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.P-CSCF in ADF.ISIM
if self.file_exists(EF_ISIM_ADF_map['PCSCF']):
if p.get('pcscf'):
sw = self.update_pcscf(p['pcscf'])
else:
sw = self.update_pcscf("")
if sw != '9000':
print("Programming P-CSCF failed with code %s"%sw)
# update EF.DOMAIN in ADF.ISIM
if self.file_exists(EF_ISIM_ADF_map['DOMAIN']):
if p.get('ims_hdomain'):
sw = self.update_domain(domain=p['ims_hdomain'])
else:
sw = self.update_domain()
if sw != '9000':
print("Programming Home Network Domain Name failed with code %s"%sw)
# update EF.IMPI in ADF.ISIM
# TODO: Validate IMPI input
if self.file_exists(EF_ISIM_ADF_map['IMPI']):
if p.get('impi'):
sw = self.update_impi(p['impi'])
else:
sw = self.update_impi()
if sw != '9000':
print("Programming IMPI failed with code %s"%sw)
# update EF.IMPU in ADF.ISIM
# TODO: Validate IMPU input
# Support multiple IMPU if there is enough space
if self.file_exists(EF_ISIM_ADF_map['IMPU']):
if p.get('impu'):
sw = self.update_impu(p['impu'])
else:
sw = self.update_impu()
if sw != '9000':
print("Programming IMPU failed with code %s"%sw)
if '9000' == self.select_adf_by_aid():
# update EF-USIM_AUTH_KEY in ADF.USIM
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)
# update EF.ePDGId in ADF.USIM
if self.file_exists(EF_USIM_ADF_map['ePDGId']):
if p.get('epdgid'):
sw = self.update_epdgid(p['epdgid'])
else:
sw = self.update_epdgid("")
if sw != '9000':
print("Programming ePDGId failed with code %s"%sw)
# update EF.ePDGSelection in ADF.USIM
if self.file_exists(EF_USIM_ADF_map['ePDGSelection']):
if p.get('epdgSelection'):
epdg_plmn = p['epdgSelection']
sw = self.update_ePDGSelection(epdg_plmn[:3], epdg_plmn[3:])
else:
sw = self.update_ePDGSelection("", "")
if sw != '9000':
print("Programming ePDGSelection failed with code %s"%sw)
# After successfully programming EF.ePDGId and EF.ePDGSelection,
# Set service 106 and 107 as available in EF.UST
# Disable service 95, 99, 115 if ISIM application is present
if self.file_exists(EF_USIM_ADF_map['UST']):
if p.get('epdgSelection') and p.get('epdgid'):
sw = self.update_ust(106, 1)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(107, 1)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(95, 0)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(99, 0)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
sw = self.update_ust(115, 0)
if sw != '9000':
print("Programming UST failed with code %s"%sw)
return None
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:
@@ -1448,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

@@ -26,15 +26,15 @@ from pySim.utils import rpad, b2h
class SimCardCommands(object):
def __init__(self, transport):
self._tp = transport
self._tp = transport;
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,12 +22,11 @@
# 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, CardConnectionException
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException
from smartcard.System import readers
from pySim.exceptions import NoCardError, ProtocolError
from pySim.exceptions import NoCardError
from pySim.transport import LinkBase
from pySim.utils import h2i, i2h
@@ -35,7 +34,7 @@ from pySim.utils import h2i, i2h
class PcscSimLink(LinkBase):
def __init__(self, reader_number=0):
r = readers()
r = readers();
self._reader = r[reader_number]
self._con = self._reader.createConnection()
@@ -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

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

View File

@@ -1,266 +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',
112: 'eCall Data over IMS',
113: 'URI support for SMS-PP DOWNLOAD as defined in 3GPP TS 31.111 [12]',
114: 'From Preferred',
115: 'IMS configuration data',
116: 'TV configuration',
117: '3GPP PS Data Off',
118: '3GPP PS Data Off Service List',
119: 'V2X',
120: 'XCAP Configuration Data',
121: 'EARFCN list for MTC/NB-IOT UEs',
122: '5GS Mobility Management Information',
123: '5G Security Parameters',
124: 'Subscription identifier privacy support',
125: 'SUCI calculation by the USIM',
126: 'UAC Access Identities support',
127: 'Expect control plane-based Steering of Roaming information during initial registration in VPLMN',
128: 'Call control on PDU Session by USIM',
}
LOCI_STATUS_map = {
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,69 +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',
20: 'WebRTC URI',
}
EF_ISIM_ADF_map = {
'IST': '6F07',
'IMPI': '6F02',
'DOMAIN': '6F03',
'IMPU': '6F04',
'AD': '6FAD',
'ARR': '6F06',
'PCSCF': '6F09',
'GBAP': '6FD5',
'GBANL': '6FD7',
'NAFKCA': '6FDD',
'UICCIARI': '6FE7',
'SMS': '6F3C',
'SMSS': '6F43',
'SMSR': '6F47',
'SMSP': '6F42',
'FromPreferred': '6FF7',
'IMSConfigData': '6FF8',
'XCAPConfigData': '6FFC',
'WebRTCURI': '6FFA'
}

View File

@@ -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,76 +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',
}
# 10.3.18 "EF.AD (Administrative data) "
EF_AD_mode_map = {
'00' : 'normal operation',
'80' : 'type approval operations',
'01' : 'normal operation + specific facilities',
'81' : 'type approval operations + specific facilities',
'02' : 'maintenance (off line)',
'04' : 'cell test operation',
}

View File

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

View File

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

View File

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

View File

@@ -1,120 +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
Administrative data: 00000002
MS operation mode: normal operation
Ciphering Indicator: disabled
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
Done !

View File

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

View File

@@ -1,136 +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
Administrative data: 00ffff02
MS operation mode: normal operation
Ciphering Indicator: enabled
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
Done !

View File

@@ -1,59 +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
Administrative data: 000000
MS operation mode: normal operation
Ciphering Indicator: disabled
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
AD: 000000
Done !

View File

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

View File

@@ -1,214 +0,0 @@
Using PC/SC reader interface
Reading ...
Autodetected card type: sysmoISIM-SJA2
ICCID: 8988211900000000025
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: 0200
MSISDN (NPI=1 ToN=3): 6766266
Administrative data: 00000002
MS operation mode: normal operation
Ciphering Indicator: disabled
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: beff9f9de73e0408400170330006002e00000000
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 106 - ePDG configuration Information support
Service 107 - ePDG configuration Information configured
Service 122 - 5GS Mobility Management Information
Service 123 - 5G Security Parameters
Service 124 - Subscription identifier privacy support
Service 126 - UAC Access Identities support
ePDGId:
Not available
ePDGSelection:
ffffffffffff # unused
ffffffffffff # unused
ffffffffffff # unused
ffffffffffff # unused
P-CSCF:
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Home Network Domain Name: Not available
IMS private user identity: Not available
IMS public user identity:
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Not available
UICC IARI:
Not available
Not available
Not available
Not available
Not available
Not available
Not available
Not available
ISIM Service Table: 190200
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,106 +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
Administrative data: 00000002
MS operation mode: normal operation
Ciphering Indicator: disabled
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
MSISDN: Not available
AD: 00000002
Done !

View File

@@ -1,57 +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
Administrative data: 000000
MS operation mode: normal operation
Ciphering Indicator: disabled
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
AD: 000000
Done !

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