Compare commits
159 Commits
users/dani
...
1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
289fd28091 | ||
|
|
92bdd5e901 | ||
|
|
c8caec2933 | ||
|
|
bdf3d3597b | ||
|
|
cebf8b198b | ||
|
|
06a1256b67 | ||
|
|
be3b64167a | ||
|
|
a97944b6ca | ||
|
|
c60192375e | ||
|
|
be7007e1d9 | ||
|
|
a5bd9684d3 | ||
|
|
0c02d8a57b | ||
|
|
3f67f9c1d3 | ||
|
|
28484d03e3 | ||
|
|
1279085f7e | ||
|
|
c491dc019f | ||
|
|
43fd03b627 | ||
|
|
654eca72c9 | ||
|
|
4779034f9e | ||
|
|
79f43dda3d | ||
|
|
556b0fe262 | ||
|
|
44e046240e | ||
|
|
05b2807168 | ||
|
|
cf727f2733 | ||
|
|
5ad9aec98f | ||
|
|
75c14c0cbd | ||
|
|
b0c7d121d7 | ||
|
|
ecbada993d | ||
|
|
3b342c2f14 | ||
|
|
acc222f9f0 | ||
|
|
f964df4eb5 | ||
|
|
3a261d31d5 | ||
|
|
5e67d5b80a | ||
|
|
3b00dbf0d2 | ||
|
|
95ec772b61 | ||
|
|
99d55552d5 | ||
|
|
95b4e8d4fa | ||
|
|
5d8cd9b378 | ||
|
|
dd014ea306 | ||
|
|
677d41bb41 | ||
|
|
de07b95f84 | ||
|
|
4a3580b4c1 | ||
|
|
f8232db327 | ||
|
|
5d0a30c19c | ||
|
|
3409ae7eea | ||
|
|
45fa604834 | ||
|
|
f394853533 | ||
|
|
d84daa12c2 | ||
|
|
dfe3dbb117 | ||
|
|
a562ea0351 | ||
|
|
4d9e6beaed | ||
|
|
8e0fccdbf3 | ||
|
|
71e38482e1 | ||
|
|
1a13c44200 | ||
|
|
8016405994 | ||
|
|
0f247f8766 | ||
|
|
1e42420e57 | ||
|
|
ca6739458e | ||
|
|
3c0bd7a41e | ||
|
|
b1634db0b3 | ||
|
|
d6a5ec51a8 | ||
|
|
e61170c0eb | ||
|
|
0e9f93fdd6 | ||
|
|
0dc8f69217 | ||
|
|
29ca8049d6 | ||
|
|
eb06b45d0e | ||
|
|
d58c632277 | ||
|
|
5c2cc66de5 | ||
|
|
cd3d6268a6 | ||
|
|
30eb8ca6aa | ||
|
|
32daaf5470 | ||
|
|
e8536c04bc | ||
|
|
7f9f64ac2a | ||
|
|
7f1d3c496f | ||
|
|
ff84c23839 | ||
|
|
b689754b49 | ||
|
|
fc83e43637 | ||
|
|
d572edef1e | ||
|
|
7d77d2d5d0 | ||
|
|
9837055f4f | ||
|
|
32f0d415af | ||
|
|
ee15c77185 | ||
|
|
df33037e42 | ||
|
|
8b72c27270 | ||
|
|
9641299f9a | ||
|
|
69e5d27e3c | ||
|
|
d3b13d0c85 | ||
|
|
0c4d82d84a | ||
|
|
3e6f16d8f6 | ||
|
|
f9f3e5e0c1 | ||
|
|
3bf43639ce | ||
|
|
475dcaa4a1 | ||
|
|
e26331ef72 | ||
|
|
441c4a768f | ||
|
|
bf5d602588 | ||
|
|
52ef675c31 | ||
|
|
6d66af653f | ||
|
|
d1fb6fc359 | ||
|
|
a850a47981 | ||
|
|
1757b263bf | ||
|
|
140844052a | ||
|
|
9efd8ef812 | ||
|
|
846cefb0cd | ||
|
|
ebe6dbaef5 | ||
|
|
e573ccb53c | ||
|
|
ad10d66baf | ||
|
|
d21349a610 | ||
|
|
c7f2f7413b | ||
|
|
98a6927b27 | ||
|
|
f9762dc98f | ||
|
|
3566b8eb55 | ||
|
|
4c306ab200 | ||
|
|
e4e98316a8 | ||
|
|
0e90e6c3c6 | ||
|
|
ab46d625fc | ||
|
|
d950786525 | ||
|
|
b3e11ea196 | ||
|
|
9664b2e7fc | ||
|
|
edf873d04a | ||
|
|
fa617ac20d | ||
|
|
41c22176e4 | ||
|
|
7ba2428de5 | ||
|
|
99affe1529 | ||
|
|
4133080ced | ||
|
|
5a541016fb | ||
|
|
4b1c763395 | ||
|
|
d24f163513 | ||
|
|
f442fb4d69 | ||
|
|
c8796a3184 | ||
|
|
2d7859759e | ||
|
|
9ca41c1f26 | ||
|
|
840a9e2a76 | ||
|
|
6af4c21cdf | ||
|
|
a3bb334981 | ||
|
|
6727f0c02c | ||
|
|
fa1dc34152 | ||
|
|
e51643e87e | ||
|
|
7947d92bc1 | ||
|
|
f829945117 | ||
|
|
0ad5bcfbc1 | ||
|
|
07cd481954 | ||
|
|
cdfdd41293 | ||
|
|
4e724391e0 | ||
|
|
76db7d7295 | ||
|
|
5a8763154e | ||
|
|
8902bcde07 | ||
|
|
84d2cb3cb3 | ||
|
|
7592eeea59 | ||
|
|
be069e26ae | ||
|
|
196b08cdfd | ||
|
|
120a000e86 | ||
|
|
1de89bf889 | ||
|
|
c5b422e2ca | ||
|
|
e053da5a14 | ||
|
|
164b963dd2 | ||
|
|
f432b2ba96 | ||
|
|
c46a4eba43 | ||
|
|
7d38d74716 | ||
|
|
9f9c60937e |
@@ -40,8 +40,8 @@ pysim requires:
|
|||||||
|
|
||||||
Example for Debian:
|
Example for Debian:
|
||||||
|
|
||||||
apt-get install python-pyscard python-serial python-pip
|
apt-get install python3-pyscard python3-serial python3-pip python3-yaml
|
||||||
pip install pytlv
|
pip3 install pytlv
|
||||||
|
|
||||||
|
|
||||||
Mailing List
|
Mailing List
|
||||||
@@ -101,7 +101,7 @@ sc = SimCardCommands(sl)
|
|||||||
sl.wait_for_card()
|
sl.wait_for_card()
|
||||||
|
|
||||||
# Print IMSI
|
# Print IMSI
|
||||||
print sc.read_binary(['3f00', '7f20', '6f07'])
|
print(sc.read_binary(['3f00', '7f20', '6f07']))
|
||||||
|
|
||||||
# Run A3/A8
|
# Run A3/A8
|
||||||
print sc.run_gsm('00112233445566778899aabbccddeeff')
|
print(sc.run_gsm('00112233445566778899aabbccddeeff'))
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ if [ ! -d "./pysim-testdata/" ] ; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
virtualenv -p python2 venv --system-site-packages
|
virtualenv -p python3 venv --system-site-packages
|
||||||
. venv/bin/activate
|
. venv/bin/activate
|
||||||
pip install pytlv
|
pip install pytlv
|
||||||
|
pip install pyyaml
|
||||||
|
|
||||||
cd pysim-testdata
|
cd pysim-testdata
|
||||||
../tests/pysim-test.sh
|
../tests/pysim-test.sh
|
||||||
|
|||||||
16
csv-format
Normal file
16
csv-format
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
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
|
||||||
422
pySim-prog.py
422
pySim-prog.py
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
#
|
#
|
||||||
# Utility to deal with sim cards and program the 'magic' ones easily
|
# Utility to deal with sim cards and program the 'magic' ones easily
|
||||||
@@ -30,6 +30,7 @@ import os
|
|||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import json
|
import json
|
||||||
@@ -38,9 +39,11 @@ except ImportError:
|
|||||||
import simplejson as json
|
import simplejson as json
|
||||||
|
|
||||||
from pySim.commands import SimCardCommands
|
from pySim.commands import SimCardCommands
|
||||||
from pySim.cards import _cards_classes
|
from pySim.cards import _cards_classes, card_detect
|
||||||
from pySim.utils import h2b, swap_nibbles, rpad, derive_milenage_opc, calculate_luhn
|
from pySim.utils import h2b, swap_nibbles, rpad, derive_milenage_opc, calculate_luhn, dec_iccid, init_reader
|
||||||
from pySim.ts_51_011 import EF
|
from pySim.ts_51_011 import EF
|
||||||
|
from pySim.card_handler import *
|
||||||
|
from pySim.utils import *
|
||||||
|
|
||||||
def parse_options():
|
def parse_options():
|
||||||
|
|
||||||
@@ -58,6 +61,14 @@ def parse_options():
|
|||||||
help="Which PC/SC reader number for SIM access",
|
help="Which PC/SC reader number for SIM access",
|
||||||
default=None,
|
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",
|
parser.add_option("--osmocon", dest="osmocon_sock", metavar="PATH",
|
||||||
help="Socket path for Calypso (e.g. Motorola C1XX) based reader (via OsmocomBB)",
|
help="Socket path for Calypso (e.g. Motorola C1XX) based reader (via OsmocomBB)",
|
||||||
default=None,
|
default=None,
|
||||||
@@ -73,6 +84,9 @@ def parse_options():
|
|||||||
parser.add_option("-a", "--pin-adm", dest="pin_adm",
|
parser.add_option("-a", "--pin-adm", dest="pin_adm",
|
||||||
help="ADM PIN used for provisioning (overwrites default)",
|
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',
|
parser.add_option("-e", "--erase", dest="erase", action='store_true',
|
||||||
help="Erase beforehand [default: %default]",
|
help="Erase beforehand [default: %default]",
|
||||||
default=False,
|
default=False,
|
||||||
@@ -92,13 +106,18 @@ def parse_options():
|
|||||||
help="Country code [default: %default]",
|
help="Country code [default: %default]",
|
||||||
default=1,
|
default=1,
|
||||||
)
|
)
|
||||||
parser.add_option("-x", "--mcc", dest="mcc", type="int",
|
parser.add_option("-x", "--mcc", dest="mcc", type="string",
|
||||||
help="Mobile Country Code [default: %default]",
|
help="Mobile Country Code [default: %default]",
|
||||||
default=901,
|
default="901",
|
||||||
)
|
)
|
||||||
parser.add_option("-y", "--mnc", dest="mnc", type="int",
|
parser.add_option("-y", "--mnc", dest="mnc", type="string",
|
||||||
help="Mobile Network Code [default: %default]",
|
help="Mobile Network Code [default: %default]",
|
||||||
default=55,
|
default="55",
|
||||||
|
)
|
||||||
|
parser.add_option("--mnclen", dest="mnclen", type="choice",
|
||||||
|
help="Length of Mobile Network Code [default: %default]",
|
||||||
|
default=2,
|
||||||
|
choices=[2, 3],
|
||||||
)
|
)
|
||||||
parser.add_option("-m", "--smsc", dest="smsc",
|
parser.add_option("-m", "--smsc", dest="smsc",
|
||||||
help="SMSC number (Start with + for international no.) [default: '00 + country code + 5555']",
|
help="SMSC number (Start with + for international no.) [default: '00 + country code + 5555']",
|
||||||
@@ -113,6 +132,9 @@ def parse_options():
|
|||||||
parser.add_option("-i", "--imsi", dest="imsi",
|
parser.add_option("-i", "--imsi", dest="imsi",
|
||||||
help="International Mobile Subscriber Identity",
|
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",
|
parser.add_option("-k", "--ki", dest="ki",
|
||||||
help="Ki (default is to randomize)",
|
help="Ki (default is to randomize)",
|
||||||
)
|
)
|
||||||
@@ -124,10 +146,31 @@ def parse_options():
|
|||||||
)
|
)
|
||||||
parser.add_option("--acc", dest="acc",
|
parser.add_option("--acc", dest="acc",
|
||||||
help="Set ACC bits (Access Control Code). not all card types are supported",
|
help="Set ACC bits (Access Control Code). not all card types are supported",
|
||||||
)
|
)
|
||||||
|
parser.add_option("--epdgid", dest="epdgid",
|
||||||
|
help="Set Home Evolved Packet Data Gateway (ePDG) Identifier. (Only FQDN format supported)",
|
||||||
|
)
|
||||||
|
parser.add_option("--epdgSelection", dest="epdgSelection",
|
||||||
|
help="Set PLMN for ePDG Selection Information. (Only Operator Identifier FQDN format supported)",
|
||||||
|
)
|
||||||
|
parser.add_option("--pcscf", dest="pcscf",
|
||||||
|
help="Set Proxy Call Session Control Function (P-CSCF) Address. (Only FQDN format supported)",
|
||||||
|
)
|
||||||
|
parser.add_option("--ims-hdomain", dest="ims_hdomain",
|
||||||
|
help="Set IMS Home Network Domain Name in FQDN format",
|
||||||
|
)
|
||||||
|
parser.add_option("--impi", dest="impi",
|
||||||
|
help="Set IMS private user identity",
|
||||||
|
)
|
||||||
|
parser.add_option("--impu", dest="impu",
|
||||||
|
help="Set IMS public user identity",
|
||||||
|
)
|
||||||
parser.add_option("--read-imsi", dest="read_imsi", action="store_true",
|
parser.add_option("--read-imsi", dest="read_imsi", action="store_true",
|
||||||
help="Read the IMSI from the CARD", default=False
|
help="Read the IMSI from the CARD", default=False
|
||||||
)
|
)
|
||||||
|
parser.add_option("--read-iccid", dest="read_iccid", action="store_true",
|
||||||
|
help="Read the ICCID from the CARD", default=False
|
||||||
|
)
|
||||||
parser.add_option("-z", "--secret", dest="secret", metavar="STR",
|
parser.add_option("-z", "--secret", dest="secret", metavar="STR",
|
||||||
help="Secret used for ICCID/IMSI autogen",
|
help="Secret used for ICCID/IMSI autogen",
|
||||||
)
|
)
|
||||||
@@ -156,20 +199,22 @@ def parse_options():
|
|||||||
parser.add_option("--dry-run", dest="dry_run",
|
parser.add_option("--dry-run", dest="dry_run",
|
||||||
help="Perform a 'dry run', don't actually program the card",
|
help="Perform a 'dry run', don't actually program the card",
|
||||||
default=False, action="store_true")
|
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()
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
if options.type == 'list':
|
if options.type == 'list':
|
||||||
for kls in _cards_classes:
|
for kls in _cards_classes:
|
||||||
print kls.name
|
print(kls.name)
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
if options.probe:
|
if options.probe:
|
||||||
return options
|
return options
|
||||||
|
|
||||||
if options.source == 'csv':
|
if options.source == 'csv':
|
||||||
if (options.imsi is None) and (options.batch_mode is False) and (options.read_imsi is False):
|
if (options.imsi is None) and (options.batch_mode is False) and (options.read_imsi is False) and (options.read_iccid is False):
|
||||||
parser.error("CSV mode needs either an IMSI, --read-imsi or batch mode")
|
parser.error("CSV mode needs either an IMSI, --read-imsi, --read-iccid or batch mode")
|
||||||
if options.read_csv is None:
|
if options.read_csv is None:
|
||||||
parser.error("CSV mode requires a CSV input file")
|
parser.error("CSV mode requires a CSV input file")
|
||||||
elif options.source == 'cmdline':
|
elif options.source == 'cmdline':
|
||||||
@@ -195,12 +240,13 @@ def parse_options():
|
|||||||
|
|
||||||
|
|
||||||
def _digits(secret, usage, len, num):
|
def _digits(secret, usage, len, num):
|
||||||
s = hashlib.sha1(secret + usage + '%d' % num)
|
seed = secret + usage + '%d' % num
|
||||||
d = ''.join(['%02d'%ord(x) for x in s.digest()])
|
s = hashlib.sha1(seed.encode())
|
||||||
|
d = ''.join(['%02d' % x for x in s.digest()])
|
||||||
return d[0:len]
|
return d[0:len]
|
||||||
|
|
||||||
def _mcc_mnc_digits(mcc, mnc):
|
def _mcc_mnc_digits(mcc, mnc):
|
||||||
return ('%03d%03d' if mnc > 100 else '%03d%02d') % (mcc, mnc)
|
return '%s%s' % (mcc, mnc)
|
||||||
|
|
||||||
def _cc_digits(cc):
|
def _cc_digits(cc):
|
||||||
return ('%03d' if cc > 100 else '%02d') % cc
|
return ('%03d' if cc > 100 else '%02d') % cc
|
||||||
@@ -230,7 +276,7 @@ def _dbi_binary_quote(s):
|
|||||||
m = sum_
|
m = sum_
|
||||||
e = i
|
e = i
|
||||||
if m == 0: # No overhead ? use this !
|
if m == 0: # No overhead ? use this !
|
||||||
break;
|
break
|
||||||
|
|
||||||
# Generate output
|
# Generate output
|
||||||
out = []
|
out = []
|
||||||
@@ -253,8 +299,17 @@ def gen_parameters(opts):
|
|||||||
mcc = opts.mcc
|
mcc = opts.mcc
|
||||||
mnc = opts.mnc
|
mnc = opts.mnc
|
||||||
|
|
||||||
if not ((0 < mcc < 999) and (0 < mnc < 999)):
|
if not mcc.isdigit() or not mnc.isdigit():
|
||||||
raise ValueError('mcc & mnc must be between 0 and 999')
|
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")
|
||||||
|
|
||||||
# Digitize country code (2 or 3 digits)
|
# Digitize country code (2 or 3 digits)
|
||||||
cc_digits = _cc_digits(opts.country)
|
cc_digits = _cc_digits(opts.country)
|
||||||
@@ -262,11 +317,26 @@ def gen_parameters(opts):
|
|||||||
# Digitize MCC/MNC (5 or 6 digits)
|
# Digitize MCC/MNC (5 or 6 digits)
|
||||||
plmn_digits = _mcc_mnc_digits(mcc, mnc)
|
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 :(
|
# ICCID (19 digits, E.118), though some phase1 vendors use 20 :(
|
||||||
if opts.iccid is not None:
|
if opts.iccid is not None:
|
||||||
iccid = opts.iccid
|
iccid = opts.iccid
|
||||||
if not _isnum(iccid, 19) and not _isnum(iccid, 20):
|
if not _isnum(iccid, 19) and not _isnum(iccid, 20):
|
||||||
raise ValueError('ICCID must be 19 or 20 digits !');
|
raise ValueError('ICCID must be 19 or 20 digits !')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
if opts.num is None:
|
if opts.num is None:
|
||||||
@@ -275,7 +345,7 @@ def gen_parameters(opts):
|
|||||||
iccid = (
|
iccid = (
|
||||||
'89' + # Common prefix (telecom)
|
'89' + # Common prefix (telecom)
|
||||||
cc_digits + # Country Code on 2/3 digits
|
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)
|
ml = 18 - len(iccid)
|
||||||
@@ -376,17 +446,16 @@ def gen_parameters(opts):
|
|||||||
else:
|
else:
|
||||||
opc = ''.join(['%02x' % random.randrange(0,256) for i in range(16)])
|
opc = ''.join(['%02x' % random.randrange(0,256) for i in range(16)])
|
||||||
|
|
||||||
if opts.pin_adm is not None:
|
pin_adm = sanitize_pin_adm(opts)
|
||||||
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 that
|
||||||
return {
|
return {
|
||||||
@@ -400,21 +469,32 @@ def gen_parameters(opts):
|
|||||||
'opc' : opc,
|
'opc' : opc,
|
||||||
'acc' : acc,
|
'acc' : acc,
|
||||||
'pin_adm' : pin_adm,
|
'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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def print_parameters(params):
|
def print_parameters(params):
|
||||||
|
|
||||||
print """Generated card parameters :
|
s = ["Generated card parameters :"]
|
||||||
> Name : %(name)s
|
if 'name' in params:
|
||||||
> SMSP : %(smsp)s
|
s.append(" > Name : %(name)s")
|
||||||
> ICCID : %(iccid)s
|
if 'smsp' in params:
|
||||||
> MCC/MNC : %(mcc)d/%(mnc)d
|
s.append(" > SMSP : %(smsp)s")
|
||||||
> IMSI : %(imsi)s
|
s.append(" > ICCID : %(iccid)s")
|
||||||
> Ki : %(ki)s
|
s.append(" > MCC/MNC : %(mcc)s/%(mnc)s")
|
||||||
> OPC : %(opc)s
|
s.append(" > IMSI : %(imsi)s")
|
||||||
> ACC : %(acc)s
|
s.append(" > Ki : %(ki)s")
|
||||||
""" % params
|
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)
|
||||||
|
|
||||||
|
|
||||||
def write_params_csv(opts, params):
|
def write_params_csv(opts, params):
|
||||||
@@ -427,30 +507,64 @@ def write_params_csv(opts, params):
|
|||||||
cw.writerow([params[x] for x in row])
|
cw.writerow([params[x] for x in row])
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
def _read_params_csv(opts, imsi):
|
def _read_params_csv(opts, iccid=None, imsi=None):
|
||||||
import csv
|
import csv
|
||||||
row = ['name', 'iccid', 'mcc', 'mnc', 'imsi', 'smsp', 'ki', 'opc']
|
|
||||||
f = open(opts.read_csv, 'r')
|
f = open(opts.read_csv, 'r')
|
||||||
cr = csv.DictReader(f, row)
|
cr = csv.DictReader(f)
|
||||||
|
|
||||||
|
# Lower-case fieldnames
|
||||||
|
cr.fieldnames = [ field.lower() for field in cr.fieldnames ]
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
|
if not 'iccid' in cr.fieldnames:
|
||||||
|
raise Exception("CSV file in wrong format!")
|
||||||
for row in cr:
|
for row in cr:
|
||||||
if opts.num is not None and opts.read_imsi is False:
|
if opts.num is not None and opts.read_iccid is False and opts.read_imsi is False:
|
||||||
if opts.num == i:
|
if opts.num == i:
|
||||||
f.close()
|
f.close()
|
||||||
return row;
|
return row
|
||||||
i += 1
|
i += 1
|
||||||
|
if row['iccid'] == iccid:
|
||||||
|
f.close()
|
||||||
|
return row
|
||||||
|
|
||||||
if row['imsi'] == imsi:
|
if row['imsi'] == imsi:
|
||||||
f.close()
|
f.close()
|
||||||
return row;
|
return row
|
||||||
|
|
||||||
f.close()
|
f.close()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def read_params_csv(opts, imsi):
|
def read_params_csv(opts, imsi=None, iccid=None):
|
||||||
row = _read_params_csv(opts, imsi)
|
row = _read_params_csv(opts, iccid=iccid, imsi=imsi)
|
||||||
if row is not None:
|
if row is not None:
|
||||||
row['mcc'] = int(row['mcc'])
|
row['mcc'] = row.get('mcc', mcc_from_imsi(row.get('imsi')))
|
||||||
row['mnc'] = int(row['mnc'])
|
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)")
|
||||||
|
|
||||||
return row
|
return row
|
||||||
|
|
||||||
|
|
||||||
@@ -500,7 +614,7 @@ def init_batch(opts):
|
|||||||
|
|
||||||
for k in BATCH_INCOMPATIBLE:
|
for k in BATCH_INCOMPATIBLE:
|
||||||
if getattr(opts, k):
|
if getattr(opts, k):
|
||||||
print "Incompatible option with batch_state: %s" % (k,)
|
print("Incompatible option with batch_state: %s" % (k,))
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
# Don't load state if there is none ...
|
# Don't load state if there is none ...
|
||||||
@@ -508,7 +622,7 @@ def init_batch(opts):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if not os.path.isfile(opts.batch_state):
|
if not os.path.isfile(opts.batch_state):
|
||||||
print "No state file yet"
|
print("No state file yet")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Get stored data
|
# Get stored data
|
||||||
@@ -531,34 +645,72 @@ def save_batch(opts):
|
|||||||
fh.close()
|
fh.close()
|
||||||
|
|
||||||
|
|
||||||
def card_detect(opts, scc):
|
def process_card(opts, first, card_handler):
|
||||||
|
|
||||||
# Detect type if needed
|
if opts.dry_run is False:
|
||||||
card = None
|
# Connect transport
|
||||||
ctypes = dict([(kls.name, kls) for kls in _cards_classes])
|
card_handler.get(first)
|
||||||
|
|
||||||
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:
|
if card is None:
|
||||||
print "Autodetection failed"
|
print("No card detected!")
|
||||||
return
|
return -1
|
||||||
|
|
||||||
if opts.type == "auto_once":
|
# Probe only
|
||||||
opts.type = card.name
|
if opts.probe:
|
||||||
|
return 0
|
||||||
|
|
||||||
elif opts.type in ctypes:
|
# Erase if requested
|
||||||
card = ctypes[opts.type](scc)
|
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
|
||||||
|
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:
|
else:
|
||||||
raise ValueError("Unknown card type: %s" % opts.type)
|
print("Dry Run: NOT PROGRAMMING!")
|
||||||
|
|
||||||
return card
|
# 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
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -567,100 +719,58 @@ if __name__ == '__main__':
|
|||||||
opts = parse_options()
|
opts = parse_options()
|
||||||
|
|
||||||
# Init card reader driver
|
# Init card reader driver
|
||||||
if opts.pcsc_dev is not None:
|
sl = init_reader(opts)
|
||||||
print("Using PC/SC reader (dev=%d) interface"
|
if sl is None:
|
||||||
% opts.pcsc_dev)
|
exit(1)
|
||||||
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
|
# Create command layer
|
||||||
scc = SimCardCommands(transport=sl)
|
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
|
# Batch mode init
|
||||||
init_batch(opts)
|
init_batch(opts)
|
||||||
|
|
||||||
|
if opts.card_handler:
|
||||||
|
card_handler = card_handler_auto(sl, opts.card_handler)
|
||||||
|
else:
|
||||||
|
card_handler = card_handler(sl)
|
||||||
|
|
||||||
# Iterate
|
# Iterate
|
||||||
done = False
|
|
||||||
first = True
|
first = True
|
||||||
card = None
|
card = None
|
||||||
|
|
||||||
while not done:
|
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
|
||||||
|
|
||||||
if opts.dry_run is False:
|
# Something did not work as well as expected, however, lets
|
||||||
# Connect transport
|
# make sure the card is pulled from the reader.
|
||||||
print "Insert card now (or CTRL-C to cancel)"
|
if rc != 0:
|
||||||
sl.wait_for_card(newcardonly=not first)
|
card_handler.error()
|
||||||
|
|
||||||
# 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':
|
|
||||||
if 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)
|
|
||||||
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 we are not in batch mode we are done in any case, so lets
|
||||||
|
# exit here.
|
||||||
if not opts.batch_mode:
|
if not opts.batch_mode:
|
||||||
done = True
|
sys.exit(rc)
|
||||||
|
|
||||||
|
first = False
|
||||||
|
|||||||
305
pySim-read.py
305
pySim-read.py
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
#
|
#
|
||||||
# Utility to display some informations about a SIM card
|
# Utility to display some informations about a SIM card
|
||||||
@@ -28,17 +28,15 @@ import os
|
|||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
from pySim.ts_51_011 import EF, DF
|
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
|
||||||
try:
|
from pySim.ts_31_103 import EF_IST_map, EF_ISIM_ADF_map
|
||||||
import json
|
|
||||||
except ImportError:
|
|
||||||
# Python < 2.5
|
|
||||||
import simplejson as json
|
|
||||||
|
|
||||||
from pySim.commands import SimCardCommands
|
from pySim.commands import SimCardCommands
|
||||||
from pySim.utils import h2b, swap_nibbles, rpad, dec_imsi, dec_iccid, format_xplmn_w_act
|
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
|
||||||
|
|
||||||
def parse_options():
|
def parse_options():
|
||||||
|
|
||||||
@@ -56,6 +54,14 @@ def parse_options():
|
|||||||
help="Which PC/SC reader number for SIM access",
|
help="Which PC/SC reader number for SIM access",
|
||||||
default=None,
|
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",
|
parser.add_option("--osmocon", dest="osmocon_sock", metavar="PATH",
|
||||||
help="Socket path for Calypso (e.g. Motorola C1XX) based reader (via OsmocomBB)",
|
help="Socket path for Calypso (e.g. Motorola C1XX) based reader (via OsmocomBB)",
|
||||||
default=None,
|
default=None,
|
||||||
@@ -75,21 +81,9 @@ if __name__ == '__main__':
|
|||||||
opts = parse_options()
|
opts = parse_options()
|
||||||
|
|
||||||
# Init card reader driver
|
# Init card reader driver
|
||||||
if opts.pcsc_dev is not None:
|
sl = init_reader(opts)
|
||||||
print("Using PC/SC reader (dev=%d) interface"
|
if sl is None:
|
||||||
% opts.pcsc_dev)
|
exit(1)
|
||||||
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
|
# Create command layer
|
||||||
scc = SimCardCommands(transport=sl)
|
scc = SimCardCommands(transport=sl)
|
||||||
@@ -97,72 +91,121 @@ if __name__ == '__main__':
|
|||||||
# Wait for SIM card
|
# Wait for SIM card
|
||||||
sl.wait_for_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
|
# Program the card
|
||||||
print("Reading ...")
|
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
|
# EF.ICCID
|
||||||
(res, sw) = scc.read_binary(EF['ICCID'])
|
(res, sw) = card.read_iccid()
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("ICCID: %s" % (dec_iccid(res),))
|
print("ICCID: %s" % (res,))
|
||||||
else:
|
else:
|
||||||
print("ICCID: Can't read, response code = %s" % (sw,))
|
print("ICCID: Can't read, response code = %s" % (sw,))
|
||||||
|
|
||||||
# EF.IMSI
|
# EF.IMSI
|
||||||
(res, sw) = scc.read_binary(['3f00', '7f20', '6f07'])
|
(res, sw) = card.read_imsi()
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("IMSI: %s" % (dec_imsi(res),))
|
print("IMSI: %s" % (res,))
|
||||||
else:
|
else:
|
||||||
print("IMSI: Can't read, response code = %s" % (sw,))
|
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
|
# EF.SMSP
|
||||||
(res, sw) = scc.read_record(['3f00', '7f10', '6f42'], 1)
|
(res, sw) = card.read_record('SMSP', 1)
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("SMSP: %s" % (res,))
|
print("SMSP: %s" % (res,))
|
||||||
else:
|
else:
|
||||||
print("SMSP: Can't read, response code = %s" % (sw,))
|
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
|
# EF.PLMNsel
|
||||||
try:
|
try:
|
||||||
(res, sw) = scc.read_binary(EF['PLMNsel'])
|
(res, sw) = card.read_binary('PLMNsel')
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("PLMNsel: %s" % (res))
|
print("PLMNsel: %s" % (res))
|
||||||
else:
|
else:
|
||||||
print("PLMNsel: Can't read, response code = %s" % (sw,))
|
print("PLMNsel: Can't read, response code = %s" % (sw,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "HPLMNAcT: Can't read file -- " + str(e)
|
print("PLMNsel: Can't read file -- " + str(e))
|
||||||
|
|
||||||
# EF.PLMNwAcT
|
# EF.PLMNwAcT
|
||||||
try:
|
try:
|
||||||
(res, sw) = scc.read_binary(EF['PLMNwAcT'])
|
(res, sw) = card.read_plmn_act()
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("PLMNwAcT:\n%s" % (format_xplmn_w_act(res)))
|
print("PLMNwAcT:\n%s" % (res))
|
||||||
else:
|
else:
|
||||||
print("PLMNwAcT: Can't read, response code = %s" % (sw,))
|
print("PLMNwAcT: Can't read, response code = %s" % (sw,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "PLMNwAcT: Can't read file -- " + str(e)
|
print("PLMNwAcT: Can't read file -- " + str(e))
|
||||||
|
|
||||||
# EF.OPLMNwAcT
|
# EF.OPLMNwAcT
|
||||||
try:
|
try:
|
||||||
(res, sw) = scc.read_binary(EF['OPLMNwAcT'])
|
(res, sw) = card.read_oplmn_act()
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("OPLMNwAcT:\n%s" % (format_xplmn_w_act(res)))
|
print("OPLMNwAcT:\n%s" % (res))
|
||||||
else:
|
else:
|
||||||
print("OPLMNwAcT: Can't read, response code = %s" % (sw,))
|
print("OPLMNwAcT: Can't read, response code = %s" % (sw,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "OPLMNwAcT: Can't read file -- " + str(e)
|
print("OPLMNwAcT: Can't read file -- " + str(e))
|
||||||
|
|
||||||
# EF.HPLMNAcT
|
# EF.HPLMNAcT
|
||||||
try:
|
try:
|
||||||
(res, sw) = scc.read_binary(EF['HPLMNAcT'])
|
(res, sw) = card.read_hplmn_act()
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("HPLMNAcT:\n%s" % (format_xplmn_w_act(res)))
|
print("HPLMNAcT:\n%s" % (res))
|
||||||
else:
|
else:
|
||||||
print("HPLMNAcT: Can't read, response code = %s" % (sw,))
|
print("HPLMNAcT: Can't read, response code = %s" % (sw,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "HPLMNAcT: Can't read file -- " + str(e)
|
print("HPLMNAcT: Can't read file -- " + str(e))
|
||||||
|
|
||||||
# EF.ACC
|
# EF.ACC
|
||||||
(res, sw) = scc.read_binary(['3f00', '7f20', '6f78'])
|
(res, sw) = card.read_binary('ACC')
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("ACC: %s" % (res,))
|
print("ACC: %s" % (res,))
|
||||||
else:
|
else:
|
||||||
@@ -170,24 +213,154 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# EF.MSISDN
|
# EF.MSISDN
|
||||||
try:
|
try:
|
||||||
# print(scc.record_size(['3f00', '7f10', '6f40']))
|
(res, sw) = card.read_msisdn()
|
||||||
(res, sw) = scc.read_record(['3f00', '7f10', '6f40'], 1)
|
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
if res[1] != 'f':
|
# (npi, ton, msisdn) = res
|
||||||
print("MSISDN: %s" % (res,))
|
if res is not None:
|
||||||
|
print("MSISDN (NPI=%d ToN=%d): %s" % res)
|
||||||
else:
|
else:
|
||||||
print("MSISDN: Not available")
|
print("MSISDN: Not available")
|
||||||
else:
|
else:
|
||||||
print("MSISDN: Can't read, response code = %s" % (sw,))
|
print("MSISDN: Can't read, response code = %s" % (sw,))
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "MSISDN: Can't read file -- " + str(e)
|
print("MSISDN: Can't read file -- " + str(e))
|
||||||
|
|
||||||
# EF.AD
|
# EF.AD
|
||||||
(res, sw) = scc.read_binary(['3f00', '7f20', '6fad'])
|
(res, sw) = card.read_binary('AD')
|
||||||
if sw == '9000':
|
if sw == '9000':
|
||||||
print("AD: %s" % (res,))
|
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")
|
||||||
else:
|
else:
|
||||||
print("AD: Can't read, response code = %s" % (sw,))
|
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 ?
|
# Done for this card and maybe for everything ?
|
||||||
print "Done !\n"
|
print("Done !\n")
|
||||||
|
|||||||
108
pySim/card_handler.py
Normal file
108
pySim/card_handler.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
#!/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("")
|
||||||
723
pySim/cards.py
723
pySim/cards.py
@@ -24,18 +24,33 @@
|
|||||||
#
|
#
|
||||||
|
|
||||||
from pySim.ts_51_011 import EF, DF
|
from pySim.ts_51_011 import EF, DF
|
||||||
|
from pySim.ts_31_102 import EF_USIM_ADF_map
|
||||||
|
from pySim.ts_31_103 import EF_ISIM_ADF_map
|
||||||
from pySim.utils import *
|
from pySim.utils import *
|
||||||
from smartcard.util import toBytes
|
from smartcard.util import toBytes
|
||||||
|
from pytlv.TLV import *
|
||||||
|
|
||||||
class Card(object):
|
class Card(object):
|
||||||
|
|
||||||
def __init__(self, scc):
|
def __init__(self, scc):
|
||||||
self._scc = scc
|
self._scc = scc
|
||||||
self._adm_chv_num = 4
|
self._adm_chv_num = 4
|
||||||
|
self._aids = []
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
self._scc.reset_card()
|
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):
|
def verify_adm(self, key):
|
||||||
'''
|
'''
|
||||||
Authenticate with ADM key
|
Authenticate with ADM key
|
||||||
@@ -65,6 +80,13 @@ class Card(object):
|
|||||||
data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4))
|
data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4))
|
||||||
return sw
|
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'):
|
def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
|
||||||
"""
|
"""
|
||||||
Update Home PLMN with access technology bit-field
|
Update Home PLMN with access technology bit-field
|
||||||
@@ -76,40 +98,54 @@ class Card(object):
|
|||||||
access_tech = 'FFFF' # All technologues selected, even Reserved for Future Use ones
|
access_tech = 'FFFF' # All technologues selected, even Reserved for Future Use ones
|
||||||
"""
|
"""
|
||||||
# get size and write EF.HPLMNwAcT
|
# get size and write EF.HPLMNwAcT
|
||||||
r = self._scc.select_file(EF['HPLMNwAcT'])
|
data = self._scc.read_binary(EF['HPLMNwAcT'], length=None, offset=0)
|
||||||
size = int(r[-1][4:8], 16)
|
size = len(data[0]) // 2
|
||||||
hplmn = enc_plmn(mcc, mnc)
|
hplmn = enc_plmn(mcc, mnc)
|
||||||
content = hplmn + access_tech
|
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
|
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'):
|
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
|
# get size and write EF.OPLMNwAcT
|
||||||
data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
|
data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
|
||||||
size = len(data[0])/2
|
size = len(data[0]) // 2
|
||||||
hplmn = enc_plmn(mcc, mnc)
|
hplmn = enc_plmn(mcc, mnc)
|
||||||
content = hplmn + access_tech
|
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
|
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'):
|
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
|
# get size and write EF.PLMNwAcT
|
||||||
data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
|
data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
|
||||||
size = len(data[0])/2
|
size = len(data[0]) // 2
|
||||||
hplmn = enc_plmn(mcc, mnc)
|
hplmn = enc_plmn(mcc, mnc)
|
||||||
content = hplmn + access_tech
|
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
|
return sw
|
||||||
|
|
||||||
def update_plmnsel(self, mcc, mnc):
|
def update_plmnsel(self, mcc, mnc):
|
||||||
data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
|
data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
|
||||||
size = len(data[0])/2
|
size = len(data[0]) // 2
|
||||||
hplmn = enc_plmn(mcc, mnc)
|
hplmn = enc_plmn(mcc, mnc)
|
||||||
data, sw = self._scc.update_binary(EF['PLMNsel'], hplmn + 'ff' * (size-3))
|
data, sw = self._scc.update_binary(EF['PLMNsel'], hplmn + 'ff' * (size-3))
|
||||||
return sw
|
return sw
|
||||||
@@ -119,16 +155,20 @@ class Card(object):
|
|||||||
return sw
|
return sw
|
||||||
|
|
||||||
def update_ad(self, mnc):
|
def update_ad(self, mnc):
|
||||||
#See also: 3GPP TS 31.102, chapter 4.2.18
|
#See also: 3GPP TS 31.102, chapter 4.2.18
|
||||||
mnclen = len(str(mnc))
|
mnclen = len(str(mnc))
|
||||||
if mnclen == 1:
|
if mnclen == 1:
|
||||||
mnclen = 2
|
mnclen = 2
|
||||||
if mnclen > 3:
|
if mnclen > 3:
|
||||||
raise RuntimeError('unable to calculate proper mnclen')
|
raise RuntimeError('unable to calculate proper mnclen')
|
||||||
|
|
||||||
data = self._scc.read_binary(EF['AD'], length=None, offset=0)
|
data, sw = self._scc.read_binary(EF['AD'], length=None, offset=0)
|
||||||
size = len(data[0])/2
|
|
||||||
content = data[0][0:6] + "%02X" % mnclen
|
# Reset contents to EF.AD in case the file is uninintalized
|
||||||
|
if data.lower() == "ffffffff":
|
||||||
|
data = "00000000"
|
||||||
|
|
||||||
|
content = data[0:6] + "%02X" % mnclen
|
||||||
data, sw = self._scc.update_binary(EF['AD'], content)
|
data, sw = self._scc.update_binary(EF['AD'], content)
|
||||||
return sw
|
return sw
|
||||||
|
|
||||||
@@ -144,6 +184,259 @@ class Card(object):
|
|||||||
data, sw = self._scc.update_binary(EF['SPN'], rpad(content, 32))
|
data, sw = self._scc.update_binary(EF['SPN'], rpad(content, 32))
|
||||||
return sw
|
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):
|
class _MagicSimBase(Card):
|
||||||
"""
|
"""
|
||||||
@@ -151,7 +444,7 @@ class _MagicSimBase(Card):
|
|||||||
each possible provider uses a specific record number in each EF. The
|
each possible provider uses a specific record number in each EF. The
|
||||||
indexes used are ( where N is the number of providers supported ) :
|
indexes used are ( where N is the number of providers supported ) :
|
||||||
- [2 .. N+1] for the operator name
|
- [2 .. N+1] for the operator name
|
||||||
- [1 .. N] for the programable EFs
|
- [1 .. N] for the programable EFs
|
||||||
|
|
||||||
* 3f00/7f4d/8f0c : Operator Name
|
* 3f00/7f4d/8f0c : Operator Name
|
||||||
|
|
||||||
@@ -188,7 +481,7 @@ class _MagicSimBase(Card):
|
|||||||
r = self._scc.select_file(['3f00', '7f4d', f[0]])
|
r = self._scc.select_file(['3f00', '7f4d', f[0]])
|
||||||
rec_len = int(r[-1][28:30], 16)
|
rec_len = int(r[-1][28:30], 16)
|
||||||
tlen = int(r[-1][4:8],16)
|
tlen = int(r[-1][4:8],16)
|
||||||
rec_cnt = (tlen / rec_len) - 1;
|
rec_cnt = (tlen / rec_len) - 1
|
||||||
|
|
||||||
if (rec_cnt < 1) or (rec_len != f[1]):
|
if (rec_cnt < 1) or (rec_len != f[1]):
|
||||||
raise RuntimeError('Bad card type')
|
raise RuntimeError('Bad card type')
|
||||||
@@ -318,7 +611,7 @@ class FakeMagicSim(Card):
|
|||||||
r = self._scc.select_file(['3f00', '000c'])
|
r = self._scc.select_file(['3f00', '000c'])
|
||||||
rec_len = int(r[-1][28:30], 16)
|
rec_len = int(r[-1][28:30], 16)
|
||||||
tlen = int(r[-1][4:8],16)
|
tlen = int(r[-1][4:8],16)
|
||||||
rec_cnt = (tlen / rec_len) - 1;
|
rec_cnt = (tlen / rec_len) - 1
|
||||||
|
|
||||||
if (rec_cnt < 1) or (rec_len != 0x5a):
|
if (rec_cnt < 1) or (rec_len != 0x5a):
|
||||||
raise RuntimeError('Bad card type')
|
raise RuntimeError('Bad card type')
|
||||||
@@ -394,7 +687,7 @@ class GrcardSim(Card):
|
|||||||
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
|
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
|
||||||
|
|
||||||
# EF.SMSP
|
# EF.SMSP
|
||||||
if p.get('smsp'):
|
if p.get('smsp'):
|
||||||
r = self._scc.select_file(['3f00', '7f10', '6f42'])
|
r = self._scc.select_file(['3f00', '7f10', '6f42'])
|
||||||
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
||||||
|
|
||||||
@@ -415,8 +708,6 @@ class GrcardSim(Card):
|
|||||||
|
|
||||||
# FIXME: EF.MSISDN
|
# FIXME: EF.MSISDN
|
||||||
|
|
||||||
def erase(self):
|
|
||||||
return
|
|
||||||
|
|
||||||
class SysmoSIMgr1(GrcardSim):
|
class SysmoSIMgr1(GrcardSim):
|
||||||
"""
|
"""
|
||||||
@@ -426,7 +717,7 @@ class SysmoSIMgr1(GrcardSim):
|
|||||||
"""
|
"""
|
||||||
name = 'sysmosim-gr1'
|
name = 'sysmosim-gr1'
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def autodetect(kls, scc):
|
def autodetect(kls, scc):
|
||||||
try:
|
try:
|
||||||
# Look for ATR
|
# Look for ATR
|
||||||
@@ -436,7 +727,7 @@ class SysmoSIMgr1(GrcardSim):
|
|||||||
return None
|
return None
|
||||||
return None
|
return None
|
||||||
|
|
||||||
class SysmoUSIMgr1(Card):
|
class SysmoUSIMgr1(UsimCard):
|
||||||
"""
|
"""
|
||||||
sysmocom sysmoUSIM-GR1
|
sysmocom sysmoUSIM-GR1
|
||||||
"""
|
"""
|
||||||
@@ -461,9 +752,6 @@ class SysmoUSIMgr1(Card):
|
|||||||
)
|
)
|
||||||
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
|
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
|
||||||
|
|
||||||
def erase(self):
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
class SysmoSIMgr2(Card):
|
class SysmoSIMgr2(Card):
|
||||||
"""
|
"""
|
||||||
@@ -484,9 +772,9 @@ class SysmoSIMgr2(Card):
|
|||||||
|
|
||||||
def program(self, p):
|
def program(self, p):
|
||||||
|
|
||||||
# select MF
|
# select MF
|
||||||
r = self._scc.select_file(['3f00'])
|
r = self._scc.select_file(['3f00'])
|
||||||
|
|
||||||
# authenticate as SUPER ADM using default key
|
# authenticate as SUPER ADM using default key
|
||||||
self._scc.verify_chv(0x0b, h2b("3838383838383838"))
|
self._scc.verify_chv(0x0b, h2b("3838383838383838"))
|
||||||
|
|
||||||
@@ -496,13 +784,13 @@ class SysmoSIMgr2(Card):
|
|||||||
# P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV 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)
|
# P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
|
||||||
if p['pin_adm']:
|
if p['pin_adm']:
|
||||||
pin = p['pin_adm']
|
pin = h2b(p['pin_adm'])
|
||||||
else:
|
else:
|
||||||
pin = h2b("4444444444444444")
|
pin = h2b("4444444444444444")
|
||||||
|
|
||||||
pdu = 'A0D43A0508' + b2h(pin)
|
pdu = 'A0D43A0508' + b2h(pin)
|
||||||
data, sw = self._scc._tp.send_apdu(pdu)
|
data, sw = self._scc._tp.send_apdu(pdu)
|
||||||
|
|
||||||
# authenticate as ADM (enough to write file, and can set PINs)
|
# authenticate as ADM (enough to write file, and can set PINs)
|
||||||
|
|
||||||
self._scc.verify_chv(0x05, pin)
|
self._scc.verify_chv(0x05, pin)
|
||||||
@@ -512,7 +800,7 @@ class SysmoSIMgr2(Card):
|
|||||||
|
|
||||||
# select DF_GSM
|
# select DF_GSM
|
||||||
r = self._scc.select_file(['7f20'])
|
r = self._scc.select_file(['7f20'])
|
||||||
|
|
||||||
# write EF.IMSI
|
# write EF.IMSI
|
||||||
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
||||||
|
|
||||||
@@ -534,15 +822,13 @@ class SysmoSIMgr2(Card):
|
|||||||
|
|
||||||
# select DF_TELECOM
|
# select DF_TELECOM
|
||||||
r = self._scc.select_file(['3f00', '7f10'])
|
r = self._scc.select_file(['3f00', '7f10'])
|
||||||
|
|
||||||
# write EF.SMSP
|
# write EF.SMSP
|
||||||
if p.get('smsp'):
|
if p.get('smsp'):
|
||||||
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
||||||
|
|
||||||
def erase(self):
|
|
||||||
return
|
|
||||||
|
|
||||||
class SysmoUSIMSJS1(Card):
|
class SysmoUSIMSJS1(UsimCard):
|
||||||
"""
|
"""
|
||||||
sysmocom sysmoUSIM-SJS1
|
sysmocom sysmoUSIM-SJS1
|
||||||
"""
|
"""
|
||||||
@@ -588,29 +874,43 @@ class SysmoUSIMSJS1(Card):
|
|||||||
content = "01" + p['opc']
|
content = "01" + p['opc']
|
||||||
data, sw = self._scc.update_binary('00F7', content)
|
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
|
# write EF.IMSI
|
||||||
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
||||||
|
|
||||||
# EF.PLMNsel
|
# EF.PLMNsel
|
||||||
if p.get('mcc') and p.get('mnc'):
|
if p.get('mcc') and p.get('mnc'):
|
||||||
sw = self.update_plmnsel(p['mcc'], p['mnc'])
|
sw = self.update_plmnsel(p['mcc'], p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming PLMNsel failed with code %s"%sw)
|
print("Programming PLMNsel failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.PLMNwAcT
|
# EF.PLMNwAcT
|
||||||
if p.get('mcc') and p.get('mnc'):
|
if p.get('mcc') and p.get('mnc'):
|
||||||
sw = self.update_plmn_act(p['mcc'], p['mnc'])
|
sw = self.update_plmn_act(p['mcc'], p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming PLMNwAcT failed with code %s"%sw)
|
print("Programming PLMNwAcT failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.OPLMNwAcT
|
# EF.OPLMNwAcT
|
||||||
if p.get('mcc') and p.get('mnc'):
|
if p.get('mcc') and p.get('mnc'):
|
||||||
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
|
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming OPLMNwAcT failed with code %s"%sw)
|
print("Programming OPLMNwAcT failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.AD
|
# EF.HPLMNwAcT
|
||||||
if p.get('mcc') and p.get('mnc'):
|
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'])
|
sw = self.update_ad(p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming AD failed with code %s"%sw)
|
print("Programming AD failed with code %s"%sw)
|
||||||
@@ -620,11 +920,19 @@ class SysmoUSIMSJS1(Card):
|
|||||||
r = self._scc.select_file(['3f00', '7f10'])
|
r = self._scc.select_file(['3f00', '7f10'])
|
||||||
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
|
||||||
|
|
||||||
def erase(self):
|
# EF.MSISDN
|
||||||
return
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
class FairwavesSIM(Card):
|
class FairwavesSIM(UsimCard):
|
||||||
"""
|
"""
|
||||||
FairwavesSIM
|
FairwavesSIM
|
||||||
|
|
||||||
@@ -636,7 +944,7 @@ class FairwavesSIM(Card):
|
|||||||
3F00/7F20/FF02: Ki
|
3F00/7F20/FF02: Ki
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = 'Fairwaves SIM'
|
name = 'Fairwaves-SIM'
|
||||||
# Propriatary files
|
# Propriatary files
|
||||||
_EF_num = {
|
_EF_num = {
|
||||||
'Ki': 'FF02',
|
'Ki': 'FF02',
|
||||||
@@ -764,17 +1072,13 @@ class FairwavesSIM(Card):
|
|||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming ACC failed with code %s"%sw)
|
print("Programming ACC failed with code %s"%sw)
|
||||||
|
|
||||||
def erase(self):
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
class OpenCellsSim(Card):
|
class OpenCellsSim(Card):
|
||||||
"""
|
"""
|
||||||
OpenCellsSim
|
OpenCellsSim
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = 'OpenCells SIM'
|
name = 'OpenCells-SIM'
|
||||||
|
|
||||||
def __init__(self, ssc):
|
def __init__(self, ssc):
|
||||||
super(OpenCellsSim, self).__init__(ssc)
|
super(OpenCellsSim, self).__init__(ssc)
|
||||||
@@ -817,7 +1121,7 @@ class OpenCellsSim(Card):
|
|||||||
# write EF.IMSI
|
# write EF.IMSI
|
||||||
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
||||||
|
|
||||||
class WavemobileSim(Card):
|
class WavemobileSim(UsimCard):
|
||||||
"""
|
"""
|
||||||
WavemobileSim
|
WavemobileSim
|
||||||
|
|
||||||
@@ -848,28 +1152,28 @@ class WavemobileSim(Card):
|
|||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
|
raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
|
||||||
|
|
||||||
# EF.ICCID
|
# EF.ICCID
|
||||||
# TODO: Add programming of the ICCID
|
# TODO: Add programming of the ICCID
|
||||||
if p.get('iccid'):
|
if p.get('iccid'):
|
||||||
print("Warning: Programming of the ICCID is not implemented for this type of card.")
|
print("Warning: Programming of the ICCID is not implemented for this type of card.")
|
||||||
|
|
||||||
# KI (Presumably a propritary file)
|
# KI (Presumably a propritary file)
|
||||||
# TODO: Add programming of KI
|
# TODO: Add programming of KI
|
||||||
if p.get('ki'):
|
if p.get('ki'):
|
||||||
print("Warning: Programming of the KI is not implemented for this type of card.")
|
print("Warning: Programming of the KI is not implemented for this type of card.")
|
||||||
|
|
||||||
# OPc (Presumably a propritary file)
|
# OPc (Presumably a propritary file)
|
||||||
# TODO: Add programming of OPc
|
# TODO: Add programming of OPc
|
||||||
if p.get('opc'):
|
if p.get('opc'):
|
||||||
print("Warning: Programming of the OPc is not implemented for this type of card.")
|
print("Warning: Programming of the OPc is not implemented for this type of card.")
|
||||||
|
|
||||||
# EF.SMSP
|
# EF.SMSP
|
||||||
if p.get('smsp'):
|
if p.get('smsp'):
|
||||||
sw = self.update_smsp(p['smsp'])
|
sw = self.update_smsp(p['smsp'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming SMSP failed with code %s"%sw)
|
print("Programming SMSP failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.IMSI
|
# EF.IMSI
|
||||||
if p.get('imsi'):
|
if p.get('imsi'):
|
||||||
sw = self.update_imsi(p['imsi'])
|
sw = self.update_imsi(p['imsi'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
@@ -882,39 +1186,260 @@ class WavemobileSim(Card):
|
|||||||
print("Programming ACC failed with code %s"%sw)
|
print("Programming ACC failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.PLMNsel
|
# EF.PLMNsel
|
||||||
if p.get('mcc') and p.get('mnc'):
|
if p.get('mcc') and p.get('mnc'):
|
||||||
sw = self.update_plmnsel(p['mcc'], p['mnc'])
|
sw = self.update_plmnsel(p['mcc'], p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming PLMNsel failed with code %s"%sw)
|
print("Programming PLMNsel failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.PLMNwAcT
|
# EF.PLMNwAcT
|
||||||
if p.get('mcc') and p.get('mnc'):
|
if p.get('mcc') and p.get('mnc'):
|
||||||
sw = self.update_plmn_act(p['mcc'], p['mnc'])
|
sw = self.update_plmn_act(p['mcc'], p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming PLMNwAcT failed with code %s"%sw)
|
print("Programming PLMNwAcT failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.OPLMNwAcT
|
# EF.OPLMNwAcT
|
||||||
if p.get('mcc') and p.get('mnc'):
|
if p.get('mcc') and p.get('mnc'):
|
||||||
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
|
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming OPLMNwAcT failed with code %s"%sw)
|
print("Programming OPLMNwAcT failed with code %s"%sw)
|
||||||
|
|
||||||
# EF.AD
|
# EF.AD
|
||||||
if p.get('mcc') and p.get('mnc'):
|
if p.get('mcc') and p.get('mnc'):
|
||||||
sw = self.update_ad(p['mnc'])
|
sw = self.update_ad(p['mnc'])
|
||||||
if sw != '9000':
|
if sw != '9000':
|
||||||
print("Programming AD failed with code %s"%sw)
|
print("Programming AD failed with code %s"%sw)
|
||||||
|
|
||||||
return None
|
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)
|
||||||
|
|
||||||
def erase(self):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
# In order for autodetection ...
|
# In order for autodetection ...
|
||||||
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
|
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
|
||||||
SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
|
SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
|
||||||
FairwavesSIM, OpenCellsSim, WavemobileSim ]
|
FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2 ]
|
||||||
|
|
||||||
def card_autodetect(scc):
|
def card_autodetect(scc):
|
||||||
for kls in _cards_classes:
|
for kls in _cards_classes:
|
||||||
@@ -923,3 +1448,31 @@ def card_autodetect(scc):
|
|||||||
card.reset()
|
card.reset()
|
||||||
return card
|
return card
|
||||||
return None
|
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
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ from pySim.utils import rpad, b2h
|
|||||||
|
|
||||||
class SimCardCommands(object):
|
class SimCardCommands(object):
|
||||||
def __init__(self, transport):
|
def __init__(self, transport):
|
||||||
self._tp = transport;
|
self._tp = transport
|
||||||
self._cla_byte = "a0"
|
self._cla_byte = "a0"
|
||||||
self.sel_ctrl = "0000"
|
self.sel_ctrl = "0000"
|
||||||
|
|
||||||
# Get file size from FCP
|
# Extract a single FCP item from TLV
|
||||||
def __get_len_from_tlv(self, fcp):
|
def __parse_fcp(self, fcp):
|
||||||
# see also: ETSI TS 102 221, chapter 11.1.1.3.1 Response for MF,
|
# see also: ETSI TS 102 221, chapter 11.1.1.3.1 Response for MF,
|
||||||
# DF or ADF
|
# 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'])
|
tlvparser = TLV(['82', '83', '84', 'a5', '8a', '8b', '8c', '80', 'ab', 'c6', '81', '88'])
|
||||||
|
|
||||||
# pytlv is case sensitive!
|
# pytlv is case sensitive!
|
||||||
@@ -49,37 +49,39 @@ class SimCardCommands(object):
|
|||||||
# what we get in the length field.
|
# what we get in the length field.
|
||||||
# See also ETSI TS 102 221, chapter 11.1.1.3.0 Base coding.
|
# See also ETSI TS 102 221, chapter 11.1.1.3.0 Base coding.
|
||||||
exp_tlv_len = int(fcp[2:4], 16)
|
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
|
skip = 4
|
||||||
else:
|
else:
|
||||||
exp_tlv_len = int(fcp[2:6], 16)
|
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 = 6
|
||||||
|
|
||||||
# Skip FCP tag and length
|
# Skip FCP tag and length
|
||||||
tlv = fcp[skip:]
|
tlv = fcp[skip:]
|
||||||
tlv_parsed = tlvparser.parse(tlv)
|
return tlvparser.parse(tlv)
|
||||||
|
|
||||||
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
|
||||||
# Tell the length of a record by the card response
|
# from what SIMs responds. See also:
|
||||||
# USIMs respond with an FCP template, which is different
|
# USIM: ETSI TS 102 221, chapter 11.1.1.3 Response Data
|
||||||
# from what SIMs responds. See also:
|
# SIM: GSM 11.11, chapter 9.2.1 SELECT
|
||||||
# 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):
|
def __record_len(self, r):
|
||||||
if self.sel_ctrl == "0004":
|
if self.sel_ctrl == "0004":
|
||||||
return self.__get_len_from_tlv(r[-1])
|
tlv_parsed = self.__parse_fcp(r[-1])
|
||||||
else:
|
file_descriptor = tlv_parsed['82']
|
||||||
return int(r[-1][28:30], 16)
|
# 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)
|
||||||
|
|
||||||
# Tell the length of a binary file. See also comment
|
# Tell the length of a binary file. See also comment
|
||||||
# above.
|
# above.
|
||||||
def __len(self, r):
|
def __len(self, r):
|
||||||
if self.sel_ctrl == "0004":
|
if self.sel_ctrl == "0004":
|
||||||
return self.__get_len_from_tlv(r[-1])
|
tlv_parsed = self.__parse_fcp(r[-1])
|
||||||
else:
|
return int(tlv_parsed['80'], 16)
|
||||||
return int(r[-1][4:8], 16)
|
else:
|
||||||
|
return int(r[-1][4:8], 16)
|
||||||
|
|
||||||
def get_atr(self):
|
def get_atr(self):
|
||||||
return self._tp.get_atr()
|
return self._tp.get_atr()
|
||||||
@@ -98,51 +100,85 @@ class SimCardCommands(object):
|
|||||||
def sel_ctrl(self, value):
|
def sel_ctrl(self, value):
|
||||||
self._sel_ctrl = value
|
self._sel_ctrl = value
|
||||||
|
|
||||||
|
def try_select_file(self, dir_list):
|
||||||
|
rv = []
|
||||||
|
if type(dir_list) is not list:
|
||||||
|
dir_list = [dir_list]
|
||||||
|
for i in dir_list:
|
||||||
|
data, sw = self._tp.send_apdu(self.cla_byte + "a4" + self.sel_ctrl + "02" + i)
|
||||||
|
rv.append((data, sw))
|
||||||
|
if sw != '9000':
|
||||||
|
return rv
|
||||||
|
return rv
|
||||||
|
|
||||||
def select_file(self, dir_list):
|
def select_file(self, dir_list):
|
||||||
rv = []
|
rv = []
|
||||||
|
if type(dir_list) is not list:
|
||||||
|
dir_list = [dir_list]
|
||||||
for i in dir_list:
|
for i in dir_list:
|
||||||
data, sw = self._tp.send_apdu_checksw(self.cla_byte + "a4" + self.sel_ctrl + "02" + i)
|
data, sw = self._tp.send_apdu_checksw(self.cla_byte + "a4" + self.sel_ctrl + "02" + i)
|
||||||
rv.append(data)
|
rv.append(data)
|
||||||
return rv
|
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):
|
def read_binary(self, ef, length=None, offset=0):
|
||||||
if not hasattr(type(ef), '__iter__'):
|
|
||||||
ef = [ef]
|
|
||||||
r = self.select_file(ef)
|
r = self.select_file(ef)
|
||||||
if len(r[-1]) == 0:
|
if len(r[-1]) == 0:
|
||||||
return (None, None)
|
return (None, None)
|
||||||
if length is None:
|
if length is None:
|
||||||
length = self.__len(r) - offset
|
length = self.__len(r) - offset
|
||||||
pdu = self.cla_byte + 'b0%04x%02x' % (offset, (min(256, length) & 0xff))
|
total_data = ''
|
||||||
return self._tp.send_apdu(pdu)
|
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
|
||||||
|
|
||||||
def update_binary(self, ef, data, offset=0):
|
def update_binary(self, ef, data, offset=0, verify=False):
|
||||||
if not hasattr(type(ef), '__iter__'):
|
|
||||||
ef = [ef]
|
|
||||||
self.select_file(ef)
|
self.select_file(ef)
|
||||||
pdu = self.cla_byte + 'd6%04x%02x' % (offset, len(data)/2) + data
|
pdu = self.cla_byte + 'd6%04x%02x' % (offset, len(data) // 2) + data
|
||||||
return self._tp.send_apdu_checksw(pdu)
|
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()))
|
||||||
|
|
||||||
def read_record(self, ef, rec_no):
|
def read_record(self, ef, rec_no):
|
||||||
if not hasattr(type(ef), '__iter__'):
|
|
||||||
ef = [ef]
|
|
||||||
r = self.select_file(ef)
|
r = self.select_file(ef)
|
||||||
rec_length = self.__record_len(r)
|
rec_length = self.__record_len(r)
|
||||||
pdu = self.cla_byte + 'b2%02x04%02x' % (rec_no, rec_length)
|
pdu = self.cla_byte + 'b2%02x04%02x' % (rec_no, rec_length)
|
||||||
return self._tp.send_apdu(pdu)
|
return self._tp.send_apdu(pdu)
|
||||||
|
|
||||||
def update_record(self, ef, rec_no, data, force_len=False):
|
def update_record(self, ef, rec_no, data, force_len=False, verify=False):
|
||||||
if not hasattr(type(ef), '__iter__'):
|
|
||||||
ef = [ef]
|
|
||||||
r = self.select_file(ef)
|
r = self.select_file(ef)
|
||||||
if not force_len:
|
if not force_len:
|
||||||
rec_length = self.__record_len(r)
|
rec_length = self.__record_len(r)
|
||||||
if (len(data)/2 != rec_length):
|
if (len(data) // 2 != rec_length):
|
||||||
raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data)/2))
|
raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data) // 2))
|
||||||
else:
|
else:
|
||||||
rec_length = len(data)/2
|
rec_length = len(data) // 2
|
||||||
pdu = (self.cla_byte + 'dc%02x04%02x' % (rec_no, rec_length)) + data
|
pdu = (self.cla_byte + 'dc%02x04%02x' % (rec_no, rec_length)) + data
|
||||||
return self._tp.send_apdu_checksw(pdu)
|
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()))
|
||||||
|
|
||||||
def record_size(self, ef):
|
def record_size(self, ef):
|
||||||
r = self.select_file(ef)
|
r = self.select_file(ef)
|
||||||
@@ -152,6 +188,10 @@ class SimCardCommands(object):
|
|||||||
r = self.select_file(ef)
|
r = self.select_file(ef)
|
||||||
return self.__len(r) // self.__record_len(r)
|
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):
|
def run_gsm(self, rand):
|
||||||
if len(rand) != 32:
|
if len(rand) != 32:
|
||||||
raise ValueError('Invalid rand')
|
raise ValueError('Invalid rand')
|
||||||
|
|||||||
@@ -23,14 +23,17 @@
|
|||||||
|
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import exceptions
|
try:
|
||||||
|
# This is for compatibility with python 2 and 3
|
||||||
|
from exceptions import Exception
|
||||||
class NoCardError(exceptions.Exception):
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ProtocolError(exceptions.Exception):
|
class NoCardError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class ReaderError(exceptions.Exception):
|
class ProtocolError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ReaderError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ class LinkBase(object):
|
|||||||
|
|
||||||
timeout : Maximum wait time (None=no timeout)
|
timeout : Maximum wait time (None=no timeout)
|
||||||
newcardonly : Should we wait for a new card, or an already
|
newcardonly : Should we wait for a new card, or an already
|
||||||
inserted one ?
|
inserted one ?
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -52,8 +52,8 @@ class LinkBase(object):
|
|||||||
|
|
||||||
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
|
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
|
||||||
return : tuple(data, sw), where
|
return : tuple(data, sw), where
|
||||||
data : string (in hex) of returned data (ex. "074F4EFFFF")
|
data : string (in hex) of returned data (ex. "074F4EFFFF")
|
||||||
sw : string (in hex) of status word (ex. "9000")
|
sw : string (in hex) of status word (ex. "9000")
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ class LinkBase(object):
|
|||||||
|
|
||||||
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
|
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
|
||||||
return : tuple(data, sw), where
|
return : tuple(data, sw), where
|
||||||
data : string (in hex) of returned data (ex. "074F4EFFFF")
|
data : string (in hex) of returned data (ex. "074F4EFFFF")
|
||||||
sw : string (in hex) of status word (ex. "9000")
|
sw : string (in hex) of status word (ex. "9000")
|
||||||
"""
|
"""
|
||||||
data, sw = self.send_apdu_raw(pdu)
|
data, sw = self.send_apdu_raw(pdu)
|
||||||
|
|
||||||
@@ -84,15 +84,15 @@ class LinkBase(object):
|
|||||||
|
|
||||||
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
|
pdu : string of hexadecimal characters (ex. "A0A40000023F00")
|
||||||
sw : string of 4 hexadecimal characters (ex. "9000"). The
|
sw : string of 4 hexadecimal characters (ex. "9000"). The
|
||||||
user may mask out certain digits using a '?' to add some
|
user may mask out certain digits using a '?' to add some
|
||||||
ambiguity if needed.
|
ambiguity if needed.
|
||||||
return : tuple(data, sw), where
|
return : tuple(data, sw), where
|
||||||
data : string (in hex) of returned data (ex. "074F4EFFFF")
|
data : string (in hex) of returned data (ex. "074F4EFFFF")
|
||||||
sw : string (in hex) of status word (ex. "9000")
|
sw : string (in hex) of status word (ex. "9000")
|
||||||
"""
|
"""
|
||||||
rv = self.send_apdu(pdu)
|
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 = ""
|
sw_masked = ""
|
||||||
for i in range(0, 4):
|
for i in range(0, 4):
|
||||||
if sw.lower()[i] == '?':
|
if sw.lower()[i] == '?':
|
||||||
|
|||||||
126
pySim/transport/modem_atcmd.py
Normal file
126
pySim/transport/modem_atcmd.py
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#!/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
|
||||||
@@ -22,11 +22,12 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from smartcard.CardConnection import CardConnection
|
||||||
from smartcard.CardRequest import CardRequest
|
from smartcard.CardRequest import CardRequest
|
||||||
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException
|
from smartcard.Exceptions import NoCardException, CardRequestTimeoutException, CardConnectionException
|
||||||
from smartcard.System import readers
|
from smartcard.System import readers
|
||||||
|
|
||||||
from pySim.exceptions import NoCardError
|
from pySim.exceptions import NoCardError, ProtocolError
|
||||||
from pySim.transport import LinkBase
|
from pySim.transport import LinkBase
|
||||||
from pySim.utils import h2i, i2h
|
from pySim.utils import h2i, i2h
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@ from pySim.utils import h2i, i2h
|
|||||||
class PcscSimLink(LinkBase):
|
class PcscSimLink(LinkBase):
|
||||||
|
|
||||||
def __init__(self, reader_number=0):
|
def __init__(self, reader_number=0):
|
||||||
r = readers();
|
r = readers()
|
||||||
self._reader = r[reader_number]
|
self._reader = r[reader_number]
|
||||||
self._con = self._reader.createConnection()
|
self._con = self._reader.createConnection()
|
||||||
|
|
||||||
@@ -52,7 +53,10 @@ class PcscSimLink(LinkBase):
|
|||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
try:
|
try:
|
||||||
self._con.connect()
|
# Explicitly select T=0 communication protocol
|
||||||
|
self._con.connect(CardConnection.T0_protocol)
|
||||||
|
except CardConnectionException:
|
||||||
|
raise ProtocolError()
|
||||||
except NoCardException:
|
except NoCardException:
|
||||||
raise NoCardError()
|
raise NoCardError()
|
||||||
|
|
||||||
@@ -63,11 +67,8 @@ class PcscSimLink(LinkBase):
|
|||||||
self._con.disconnect()
|
self._con.disconnect()
|
||||||
|
|
||||||
def reset_card(self):
|
def reset_card(self):
|
||||||
self._con.disconnect()
|
self.disconnect()
|
||||||
try:
|
self.connect()
|
||||||
self._con.connect()
|
|
||||||
except NoCardException:
|
|
||||||
raise NoCardError()
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
def send_apdu_raw(self, pdu):
|
def send_apdu_raw(self, pdu):
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from __future__ import absolute_import
|
|||||||
|
|
||||||
import serial
|
import serial
|
||||||
import time
|
import time
|
||||||
|
import os.path
|
||||||
|
|
||||||
from pySim.exceptions import NoCardError, ProtocolError
|
from pySim.exceptions import NoCardError, ProtocolError
|
||||||
from pySim.transport import LinkBase
|
from pySim.transport import LinkBase
|
||||||
@@ -34,6 +35,8 @@ from pySim.utils import h2b, b2h
|
|||||||
class SerialSimLink(LinkBase):
|
class SerialSimLink(LinkBase):
|
||||||
|
|
||||||
def __init__(self, device='/dev/ttyUSB0', baudrate=9600, rst='-rts', debug=False):
|
def __init__(self, device='/dev/ttyUSB0', baudrate=9600, rst='-rts', debug=False):
|
||||||
|
if not os.path.exists(device):
|
||||||
|
raise ValueError("device file %s does not exist -- abort" % device)
|
||||||
self._sl = serial.Serial(
|
self._sl = serial.Serial(
|
||||||
port = device,
|
port = device,
|
||||||
parity = serial.PARITY_EVEN,
|
parity = serial.PARITY_EVEN,
|
||||||
@@ -49,7 +52,8 @@ class SerialSimLink(LinkBase):
|
|||||||
self._atr = None
|
self._atr = None
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self._sl.close()
|
if (hasattr(self, "_sl")):
|
||||||
|
self._sl.close()
|
||||||
|
|
||||||
def wait_for_card(self, timeout=None, newcardonly=False):
|
def wait_for_card(self, timeout=None, newcardonly=False):
|
||||||
# Direct try
|
# Direct try
|
||||||
@@ -117,7 +121,7 @@ class SerialSimLink(LinkBase):
|
|||||||
rst_meth = rst_meth_map[self._rst_pin[1:]]
|
rst_meth = rst_meth_map[self._rst_pin[1:]]
|
||||||
rst_val = rst_val_map[self._rst_pin[0]]
|
rst_val = rst_val_map[self._rst_pin[0]]
|
||||||
except:
|
except:
|
||||||
raise ValueError('Invalid reset pin %s' % self._rst_pin);
|
raise ValueError('Invalid reset pin %s' % self._rst_pin)
|
||||||
|
|
||||||
rst_meth(rst_val)
|
rst_meth(rst_val)
|
||||||
time.sleep(0.1) # 100 ms
|
time.sleep(0.1) # 100 ms
|
||||||
@@ -128,7 +132,7 @@ class SerialSimLink(LinkBase):
|
|||||||
if not b:
|
if not b:
|
||||||
return 0
|
return 0
|
||||||
if ord(b) != 0x3b:
|
if ord(b) != 0x3b:
|
||||||
return -1;
|
return -1
|
||||||
self._dbg_print("TS: 0x%x Direct convention" % ord(b))
|
self._dbg_print("TS: 0x%x Direct convention" % ord(b))
|
||||||
|
|
||||||
while ord(b) == 0x3b:
|
while ord(b) == 0x3b:
|
||||||
@@ -162,7 +166,7 @@ class SerialSimLink(LinkBase):
|
|||||||
|
|
||||||
def _dbg_print(self, s):
|
def _dbg_print(self, s):
|
||||||
if self._debug:
|
if self._debug:
|
||||||
print s
|
print(s)
|
||||||
|
|
||||||
def _tx_byte(self, b):
|
def _tx_byte(self, b):
|
||||||
self._sl.write(b)
|
self._sl.write(b)
|
||||||
@@ -213,7 +217,7 @@ class SerialSimLink(LinkBase):
|
|||||||
self._tx_string(pdu[5:])
|
self._tx_string(pdu[5:])
|
||||||
|
|
||||||
# Receive data (including SW !)
|
# 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
|
to_recv = data_len - len(pdu) + 5 + 2
|
||||||
|
|
||||||
data = ''
|
data = ''
|
||||||
@@ -222,7 +226,7 @@ class SerialSimLink(LinkBase):
|
|||||||
if (to_recv == 2) and (b == '\x60'): # Ignore NIL if we have no RX data (hack ?)
|
if (to_recv == 2) and (b == '\x60'): # Ignore NIL if we have no RX data (hack ?)
|
||||||
continue
|
continue
|
||||||
if not b:
|
if not b:
|
||||||
break;
|
break
|
||||||
data += b
|
data += b
|
||||||
|
|
||||||
# Split datafield from SW
|
# Split datafield from SW
|
||||||
|
|||||||
266
pySim/ts_31_102.py
Normal file
266
pySim/ts_31_102.py
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
#!/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',
|
||||||
|
}
|
||||||
69
pySim/ts_31_103.py
Normal file
69
pySim/ts_31_103.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/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'
|
||||||
|
}
|
||||||
@@ -48,6 +48,7 @@ EF_num = {
|
|||||||
# MF
|
# MF
|
||||||
'ICCID': '2FE2',
|
'ICCID': '2FE2',
|
||||||
'ELP': '2F05',
|
'ELP': '2F05',
|
||||||
|
'DIR': '2F00',
|
||||||
|
|
||||||
# DF_TELECOM
|
# DF_TELECOM
|
||||||
'ADN': '6F3A',
|
'ADN': '6F3A',
|
||||||
@@ -164,6 +165,7 @@ DF = {
|
|||||||
EF = {
|
EF = {
|
||||||
'ICCID': [MF_num, EF_num['ICCID']],
|
'ICCID': [MF_num, EF_num['ICCID']],
|
||||||
'ELP': [MF_num, EF_num['ELP']],
|
'ELP': [MF_num, EF_num['ELP']],
|
||||||
|
'DIR': [MF_num, EF_num['DIR']],
|
||||||
|
|
||||||
'ADN': DF['TELECOM']+[EF_num['ADN']],
|
'ADN': DF['TELECOM']+[EF_num['ADN']],
|
||||||
'FDN': DF['TELECOM']+[EF_num['FDN']],
|
'FDN': DF['TELECOM']+[EF_num['FDN']],
|
||||||
@@ -249,3 +251,76 @@ EF = {
|
|||||||
'MMSUP': DF['GSM']+[EF_num['MMSUP']],
|
'MMSUP': DF['GSM']+[EF_num['MMSUP']],
|
||||||
'MMSUCP': DF['GSM']+[EF_num['MMSUCP']],
|
'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',
|
||||||
|
}
|
||||||
|
|||||||
604
pySim/utils.py
604
pySim/utils.py
@@ -35,11 +35,16 @@ def i2h(s):
|
|||||||
return ''.join(['%02x'%(x) for x in s])
|
return ''.join(['%02x'%(x) for x in s])
|
||||||
|
|
||||||
def h2s(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 not (x == 'f' and y == 'f') ])
|
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])
|
||||||
|
|
||||||
def s2h(s):
|
def s2h(s):
|
||||||
return b2h(s)
|
return b2h(s)
|
||||||
|
|
||||||
|
# List of bytes to string
|
||||||
|
def i2s(s):
|
||||||
|
return ''.join([chr(x) for x in s])
|
||||||
|
|
||||||
def swap_nibbles(s):
|
def swap_nibbles(s):
|
||||||
return ''.join([x+y for x,y in zip(s[1::2], s[0::2])])
|
return ''.join([x+y for x,y in zip(s[1::2], s[0::2])])
|
||||||
|
|
||||||
@@ -81,6 +86,8 @@ def dec_imsi(ef):
|
|||||||
l = int(ef[0:2], 16) * 2 # Length of the IMSI string
|
l = int(ef[0:2], 16) * 2 # Length of the IMSI string
|
||||||
l = l - 1 # Encoded length byte includes oe nibble
|
l = l - 1 # Encoded length byte includes oe nibble
|
||||||
swapped = swap_nibbles(ef[2:]).rstrip('f')
|
swapped = swap_nibbles(ef[2:]).rstrip('f')
|
||||||
|
if len(swapped) < 1:
|
||||||
|
return None
|
||||||
oe = (int(swapped[0])>>3) & 1 # Odd (1) / Even (0)
|
oe = (int(swapped[0])>>3) & 1 # Odd (1) / Even (0)
|
||||||
if not oe:
|
if not oe:
|
||||||
# if even, only half of last byte was used
|
# if even, only half of last byte was used
|
||||||
@@ -98,7 +105,9 @@ def enc_iccid(iccid):
|
|||||||
|
|
||||||
def enc_plmn(mcc, mnc):
|
def enc_plmn(mcc, mnc):
|
||||||
"""Converts integer MCC/MNC into 3 bytes for EF"""
|
"""Converts integer MCC/MNC into 3 bytes for EF"""
|
||||||
return swap_nibbles(lpad('%d' % mcc, 3) + lpad('%d' % mnc, 3))
|
if len(mnc) == 2:
|
||||||
|
mnc = "F%s" % mnc
|
||||||
|
return swap_nibbles("%s%s" % (mcc, mnc))
|
||||||
|
|
||||||
def dec_spn(ef):
|
def dec_spn(ef):
|
||||||
byte1 = int(ef[0:2])
|
byte1 = int(ef[0:2])
|
||||||
@@ -113,8 +122,8 @@ def enc_spn(name, hplmn_disp=False, oplmn_disp=False):
|
|||||||
if oplmn_disp: byte1 = byte1|0x02
|
if oplmn_disp: byte1 = byte1|0x02
|
||||||
return i2h([byte1])+s2h(name)
|
return i2h([byte1])+s2h(name)
|
||||||
|
|
||||||
def hexstr_to_fivebytearr(s):
|
def hexstr_to_Nbytearr(s, nbytes):
|
||||||
return [s[i:i+10] for i in range(0, len(s), 10) ]
|
return [s[i:i+(nbytes*2)] for i in range(0, len(s), (nbytes*2)) ]
|
||||||
|
|
||||||
# Accepts hex string representing three bytes
|
# Accepts hex string representing three bytes
|
||||||
def dec_mcc_from_plmn(plmn):
|
def dec_mcc_from_plmn(plmn):
|
||||||
@@ -124,28 +133,16 @@ def dec_mcc_from_plmn(plmn):
|
|||||||
digit3 = ia[1] & 0x0F # 2nd byte, LSB
|
digit3 = ia[1] & 0x0F # 2nd byte, LSB
|
||||||
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
|
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
|
||||||
return 0xFFF # 4095
|
return 0xFFF # 4095
|
||||||
mcc = digit1 * 100
|
return derive_mcc(digit1, digit2, digit3)
|
||||||
mcc += digit2 * 10
|
|
||||||
mcc += digit3
|
|
||||||
return mcc
|
|
||||||
|
|
||||||
def dec_mnc_from_plmn(plmn):
|
def dec_mnc_from_plmn(plmn):
|
||||||
ia = h2i(plmn)
|
ia = h2i(plmn)
|
||||||
digit1 = ia[2] & 0x0F # 3rd byte, LSB
|
digit1 = (ia[1] & 0xF0) >>4 # 2nd byte, MSB
|
||||||
digit2 = (ia[2] & 0xF0) >> 4 # 3rd byte, MSB
|
digit2 = ia[2] & 0x0F # 3rd byte, LSB
|
||||||
digit3 = (ia[1] & 0xF0) >> 4 # 2nd byte, MSB
|
digit3 = (ia[2] & 0xF0) >> 4 # 3nd byte, MSB
|
||||||
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
|
if digit3 == 0xF and digit2 == 0xF and digit1 == 0xF:
|
||||||
return 0xFFF # 4095
|
return 0xFFF # 4095
|
||||||
mnc = 0
|
return derive_mnc(digit1, digit2, digit3)
|
||||||
# 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):
|
def dec_act(twohexbytes):
|
||||||
act_list = [
|
act_list = [
|
||||||
@@ -177,12 +174,61 @@ def dec_xplmn_w_act(fivehexbytes):
|
|||||||
|
|
||||||
def format_xplmn_w_act(hexstr):
|
def format_xplmn_w_act(hexstr):
|
||||||
s = ""
|
s = ""
|
||||||
for rec_data in hexstr_to_fivebytearr(hexstr):
|
for rec_data in hexstr_to_Nbytearr(hexstr, 5):
|
||||||
rec_info = dec_xplmn_w_act(rec_data)
|
rec_info = dec_xplmn_w_act(rec_data)
|
||||||
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
|
if rec_info['mcc'] == 0xFFF and rec_info['mnc'] == 0xFFF:
|
||||||
rec_str = "unused"
|
rec_str = "unused"
|
||||||
else:
|
else:
|
||||||
rec_str = "MCC: %3s MNC: %3s AcT: %s" % (rec_info['mcc'], rec_info['mnc'], ", ".join(rec_info['act']))
|
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'])
|
||||||
s += "\t%s # %s\n" % (rec_data, rec_str)
|
s += "\t%s # %s\n" % (rec_data, rec_str)
|
||||||
return s
|
return s
|
||||||
|
|
||||||
@@ -203,6 +249,516 @@ def calculate_luhn(cc):
|
|||||||
"""
|
"""
|
||||||
Calculate Luhn checksum used in e.g. ICCID and IMEI
|
Calculate Luhn checksum used in e.g. ICCID and IMEI
|
||||||
"""
|
"""
|
||||||
num = map(int, str(cc))
|
num = list(map(int, str(cc)))
|
||||||
check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
|
check_digit = 10 - sum(num[-2::-2] + [sum(divmod(d * 2, 10)) for d in num[::-2]]) % 10
|
||||||
return 0 if check_digit == 10 else check_digit
|
return 0 if check_digit == 10 else check_digit
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class DecTestCase(unittest.TestCase):
|
|||||||
"ffffff0002",
|
"ffffff0002",
|
||||||
"ffffff0001",
|
"ffffff0001",
|
||||||
]
|
]
|
||||||
self.assertEqual(utils.hexstr_to_fivebytearr(input_str), expected)
|
self.assertEqual(utils.hexstr_to_Nbytearr(input_str, 5), expected)
|
||||||
|
|
||||||
def testDecMCCfromPLMN(self):
|
def testDecMCCfromPLMN(self):
|
||||||
self.assertEqual(utils.dec_mcc_from_plmn("92f501"), 295)
|
self.assertEqual(utils.dec_mcc_from_plmn("92f501"), 295)
|
||||||
|
|||||||
5
pysim-testdata/Fairwaves-SIM.data
Normal file
5
pysim-testdata/Fairwaves-SIM.data
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
MCC=001
|
||||||
|
MNC=01
|
||||||
|
IMSI=001010000000111
|
||||||
|
ADM_HEX=CAE743DB9C5B5A58
|
||||||
|
|
||||||
120
pysim-testdata/Fairwaves-SIM.ok
Normal file
120
pysim-testdata/Fairwaves-SIM.ok
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
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 !
|
||||||
|
|
||||||
5
pysim-testdata/Wavemobile-SIM.data
Normal file
5
pysim-testdata/Wavemobile-SIM.data
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
MCC=001
|
||||||
|
MNC=01
|
||||||
|
IMSI=001010000000102
|
||||||
|
ADM_HEX=15E31383624FDC8A
|
||||||
|
|
||||||
136
pysim-testdata/Wavemobile-SIM.ok
Normal file
136
pysim-testdata/Wavemobile-SIM.ok
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
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 !
|
||||||
|
|
||||||
@@ -1,14 +1,59 @@
|
|||||||
Using PC/SC reader (dev=1) interface
|
Using PC/SC reader interface
|
||||||
Reading ...
|
Reading ...
|
||||||
|
Autodetected card type: fakemagicsim
|
||||||
|
Can't read AIDs from SIM -- SW match failed! Expected 9000 and got 9404.
|
||||||
ICCID: 1122334455667788990
|
ICCID: 1122334455667788990
|
||||||
IMSI: 001010000000102
|
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
|
SMSP: ffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
|
||||||
PLMNsel: fff11fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
SPN: Magic
|
||||||
|
Display HPLMN: True
|
||||||
|
Display OPLMN: False
|
||||||
|
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
PLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
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.
|
OPLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||||
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||||
ACC: ffff
|
ACC: ffff
|
||||||
MSISDN: Not available
|
MSISDN: Not available
|
||||||
AD: 000000
|
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
|
||||||
|
|
||||||
Done !
|
Done !
|
||||||
|
|
||||||
|
|||||||
7
pysim-testdata/sysmoISIM-SJA2.data
Normal file
7
pysim-testdata/sysmoISIM-SJA2.data
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
MCC=001
|
||||||
|
MNC=01
|
||||||
|
ICCID=1122334455667788990
|
||||||
|
KI=AABBCCDDEEFFAABBCCDDEEFFAABBCCDD
|
||||||
|
OPC=12345678901234567890123456789012
|
||||||
|
IMSI=001010000000102
|
||||||
|
ADM=11111111
|
||||||
214
pysim-testdata/sysmoISIM-SJA2.ok
Normal file
214
pysim-testdata/sysmoISIM-SJA2.ok
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
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 !
|
||||||
|
|
||||||
@@ -4,4 +4,5 @@ ICCID=1122334455667788990
|
|||||||
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
IMSI=001010000000102
|
IMSI=001010000000102
|
||||||
|
MSISDN=+77776336143
|
||||||
ADM=55538407
|
ADM=55538407
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
Using PC/SC reader (dev=0) interface
|
Using PC/SC reader interface
|
||||||
Reading ...
|
Reading ...
|
||||||
|
Autodetected card type: sysmoUSIM-SJS1
|
||||||
ICCID: 1122334455667788990
|
ICCID: 1122334455667788990
|
||||||
IMSI: 001010000000102
|
IMSI: 001010000000102
|
||||||
|
GID1: ffffffffffffffffffff
|
||||||
|
GID2: ffffffffffffffffffff
|
||||||
SMSP: ffffffffffffffffffffffffffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
|
SMSP: ffffffffffffffffffffffffffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
|
||||||
PLMNsel: fff11fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
SPN: Magic
|
||||||
|
Display HPLMN: True
|
||||||
|
Display OPLMN: True
|
||||||
|
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
PLMNwAcT:
|
PLMNwAcT:
|
||||||
fff11fffff # MCC: 1651 MNC: 151 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
|
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
|
||||||
@@ -19,7 +25,7 @@ PLMNwAcT:
|
|||||||
ffffff0000 # unused
|
ffffff0000 # unused
|
||||||
|
|
||||||
OPLMNwAcT:
|
OPLMNwAcT:
|
||||||
fff11fffff # MCC: 1651 MNC: 151 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
|
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
|
||||||
@@ -33,21 +39,106 @@ OPLMNwAcT:
|
|||||||
ffffff0000 # unused
|
ffffff0000 # unused
|
||||||
|
|
||||||
HPLMNAcT:
|
HPLMNAcT:
|
||||||
ffffffffff # unused
|
00f110ffff # MCC: 001 MNC: 001 AcT: UTRAN, E-UTRAN, GSM, GSM COMPACT, cdma2000 HRPD, cdma2000 1xRTT
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
ffffffffff # unused
|
ffffff0000 # unused
|
||||||
|
|
||||||
ACC: 0008
|
ACC: 0008
|
||||||
MSISDN: Not available
|
MSISDN (NPI=1 ToN=1): +77776336143
|
||||||
AD: 00000002
|
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
|
||||||
|
|
||||||
Done !
|
Done !
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,57 @@
|
|||||||
Using PC/SC reader (dev=2) interface
|
Using PC/SC reader interface
|
||||||
Reading ...
|
Reading ...
|
||||||
|
Autodetected card type: sysmosim-gr1
|
||||||
|
Can't read AIDs from SIM -- SW match failed! Expected 9000 and got 9404.
|
||||||
ICCID: 1122334455667788990
|
ICCID: 1122334455667788990
|
||||||
IMSI: 001010000000102
|
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
|
SMSP: ffffffffffffffffffffffffe1ffffffffffffffffffffffff0581005155f5ffffffffffff000000
|
||||||
PLMNsel: fff11fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
SPN: Not available
|
||||||
|
Display HPLMN: False
|
||||||
|
Display OPLMN: False
|
||||||
|
PLMNsel: 00f110ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
|
||||||
PLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
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.
|
OPLMNwAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||||
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
HPLMNAcT: Can't read file -- SW match failed! Expected 9000 and got 9404.
|
||||||
ACC: 0008
|
ACC: 0008
|
||||||
MSISDN: Not available
|
MSISDN: Not available
|
||||||
AD: 000000
|
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
|
||||||
|
|
||||||
Done !
|
Done !
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
MCC=001
|
MCC=001
|
||||||
MNC=01
|
MNC=01
|
||||||
IMSI=001010000000102
|
IMSI=001010000000102
|
||||||
ADM=0123456789ABCDEF
|
ADM_HEX=0123456789ABCDEF
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ function check_card {
|
|||||||
echo "------------8<------------"
|
echo "------------8<------------"
|
||||||
cat $TEMPFILE
|
cat $TEMPFILE
|
||||||
echo "------------8<------------"
|
echo "------------8<------------"
|
||||||
|
rm *.tmp
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -155,10 +156,17 @@ function run_test {
|
|||||||
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
IMSI=001010000000001
|
IMSI=001010000000001
|
||||||
|
MSISDN=6766266
|
||||||
ADM=00000000
|
ADM=00000000
|
||||||
|
ADM_HEX=""
|
||||||
|
ADM_OPT="-a"
|
||||||
|
|
||||||
. "$CARD_NAME.data"
|
source "$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
|
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
|
||||||
check_card $I $CARD_NAME
|
check_card $I $CARD_NAME
|
||||||
echo ""
|
echo ""
|
||||||
done
|
done
|
||||||
|
|||||||
@@ -4,4 +4,5 @@ ICCID=1122334455667788990
|
|||||||
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
KI=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
OPC=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
|
||||||
IMSI=001010000000102
|
IMSI=001010000000102
|
||||||
|
MSISDN=+77776336143
|
||||||
ADM=12345678
|
ADM=12345678
|
||||||
|
|||||||
Reference in New Issue
Block a user