2010-12-06 23:24:32 +00:00
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
""" pySim: Card programmation logic
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
#
|
|
|
|
|
# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
|
2011-03-22 20:48:19 +00:00
|
|
|
|
# Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
|
2017-07-18 14:04:38 +00:00
|
|
|
|
# Copyright (C) 2017 Alexander.Chemeris <Alexander.Chemeris@gmail.com>
|
2010-12-06 23:24:32 +00:00
|
|
|
|
#
|
|
|
|
|
# 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/>.
|
|
|
|
|
#
|
|
|
|
|
|
2021-05-02 00:10:39 +00:00
|
|
|
|
from typing import Optional, Dict, Tuple
|
2021-05-02 00:18:42 +00:00
|
|
|
|
import abc
|
2021-05-02 00:10:39 +00:00
|
|
|
|
|
2021-05-07 13:23:20 +00:00
|
|
|
|
from pySim.ts_51_011 import EF, DF, EF_AD, EF_SPN
|
2020-06-03 13:19:40 +00:00
|
|
|
|
from pySim.ts_31_102 import EF_USIM_ADF_map
|
2020-03-24 16:26:40 +00:00
|
|
|
|
from pySim.ts_31_103 import EF_ISIM_ADF_map
|
2017-07-18 14:04:38 +00:00
|
|
|
|
from pySim.utils import *
|
2018-01-10 05:17:55 +00:00
|
|
|
|
from smartcard.util import toBytes
|
2020-03-25 10:43:19 +00:00
|
|
|
|
from pytlv.TLV import *
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
2021-04-30 13:00:27 +00:00
|
|
|
|
def format_addr(addr:str, addr_type:str) -> str:
|
|
|
|
|
"""
|
|
|
|
|
helper function to format an FQDN (addr_type = '00') or IPv4
|
|
|
|
|
(addr_type = '01') address string into a printable string that
|
|
|
|
|
contains the hexadecimal representation and the original address
|
|
|
|
|
string (addr)
|
|
|
|
|
"""
|
|
|
|
|
res = ""
|
|
|
|
|
if addr_type == '00': #FQDN
|
|
|
|
|
res += "\t%s # %s\n" % (s2h(addr), addr)
|
|
|
|
|
elif addr_type == '01': #IPv4
|
|
|
|
|
octets = addr.split(".")
|
|
|
|
|
addr_hex = ""
|
|
|
|
|
for o in octets:
|
|
|
|
|
addr_hex += ("%02x" % int(o))
|
|
|
|
|
res += "\t%s # %s\n" % (addr_hex, addr)
|
|
|
|
|
return res
|
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class SimCard(object):
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
2021-05-05 10:18:41 +00:00
|
|
|
|
name = 'SIM'
|
|
|
|
|
|
2010-12-06 23:24:32 +00:00
|
|
|
|
def __init__(self, scc):
|
|
|
|
|
self._scc = scc
|
2017-07-18 14:04:38 +00:00
|
|
|
|
self._adm_chv_num = 4
|
2020-03-18 10:33:14 +00:00
|
|
|
|
self._aids = []
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
def reset(self):
|
2021-10-29 16:31:03 +00:00
|
|
|
|
rc = self._scc.reset_card()
|
|
|
|
|
if rc is 1:
|
|
|
|
|
return self._scc.get_atr()
|
|
|
|
|
else:
|
|
|
|
|
return None
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
2020-05-12 14:47:45 +00:00
|
|
|
|
def erase(self):
|
|
|
|
|
print("warning: erasing is not supported for specified card type!")
|
|
|
|
|
return
|
|
|
|
|
|
2020-06-03 13:19:40 +00:00
|
|
|
|
def file_exists(self, fid):
|
2021-01-21 15:06:50 +00:00
|
|
|
|
res_arr = self._scc.try_select_path(fid)
|
2020-06-03 13:19:40 +00:00
|
|
|
|
for res in res_arr:
|
2020-08-31 13:04:19 +00:00
|
|
|
|
if res[1] != '9000':
|
|
|
|
|
return False
|
2020-06-03 13:19:40 +00:00
|
|
|
|
return True
|
|
|
|
|
|
2017-07-18 14:04:38 +00:00
|
|
|
|
def verify_adm(self, key):
|
2021-10-29 14:35:22 +00:00
|
|
|
|
"""Authenticate with ADM key"""
|
2017-07-18 14:04:38 +00:00
|
|
|
|
(res, sw) = self._scc.verify_chv(self._adm_chv_num, key)
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
def read_iccid(self):
|
|
|
|
|
(res, sw) = self._scc.read_binary(EF['ICCID'])
|
|
|
|
|
if sw == '9000':
|
|
|
|
|
return (dec_iccid(res), sw)
|
|
|
|
|
else:
|
|
|
|
|
return (None, sw)
|
|
|
|
|
|
|
|
|
|
def read_imsi(self):
|
|
|
|
|
(res, sw) = self._scc.read_binary(EF['IMSI'])
|
|
|
|
|
if sw == '9000':
|
|
|
|
|
return (dec_imsi(res), sw)
|
|
|
|
|
else:
|
|
|
|
|
return (None, sw)
|
|
|
|
|
|
|
|
|
|
def update_imsi(self, imsi):
|
|
|
|
|
data, sw = self._scc.update_binary(EF['IMSI'], enc_imsi(imsi))
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
def update_acc(self, acc):
|
2021-04-01 14:14:27 +00:00
|
|
|
|
data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4, c='0'))
|
2017-07-18 14:04:38 +00:00
|
|
|
|
return sw
|
|
|
|
|
|
2020-03-19 11:44:11 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2017-07-18 14:04:38 +00:00
|
|
|
|
def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
|
|
|
|
|
"""
|
|
|
|
|
Update Home PLMN with access technology bit-field
|
|
|
|
|
|
|
|
|
|
See Section "10.3.37 EFHPLMNwAcT (HPLMN Selector with Access Technology)"
|
|
|
|
|
in ETSI TS 151 011 for the details of the access_tech field coding.
|
|
|
|
|
Some common values:
|
|
|
|
|
access_tech = '0080' # Only GSM is selected
|
2021-04-11 08:28:28 +00:00
|
|
|
|
access_tech = 'FFFF' # All technologies selected, even Reserved for Future Use ones
|
2017-07-18 14:04:38 +00:00
|
|
|
|
"""
|
|
|
|
|
# get size and write EF.HPLMNwAcT
|
2019-11-30 10:00:10 +00:00
|
|
|
|
data = self._scc.read_binary(EF['HPLMNwAcT'], length=None, offset=0)
|
2020-02-26 18:49:51 +00:00
|
|
|
|
size = len(data[0]) // 2
|
2017-07-18 14:04:38 +00:00
|
|
|
|
hplmn = enc_plmn(mcc, mnc)
|
|
|
|
|
content = hplmn + access_tech
|
2020-02-26 18:49:51 +00:00
|
|
|
|
data, sw = self._scc.update_binary(EF['HPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
|
2017-07-18 14:04:38 +00:00
|
|
|
|
return sw
|
|
|
|
|
|
2020-03-19 11:43:11 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2018-07-04 15:57:20 +00:00
|
|
|
|
def update_oplmn_act(self, mcc, mnc, access_tech='FFFF'):
|
2021-10-29 14:35:22 +00:00
|
|
|
|
"""get size and write EF.OPLMNwAcT, See note in update_hplmn_act()"""
|
2019-09-11 23:46:25 +00:00
|
|
|
|
data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
|
2020-02-14 22:03:09 +00:00
|
|
|
|
size = len(data[0]) // 2
|
2018-07-04 15:57:20 +00:00
|
|
|
|
hplmn = enc_plmn(mcc, mnc)
|
|
|
|
|
content = hplmn + access_tech
|
2020-02-26 18:49:51 +00:00
|
|
|
|
data, sw = self._scc.update_binary(EF['OPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
|
2018-07-04 15:57:20 +00:00
|
|
|
|
return sw
|
|
|
|
|
|
2020-03-19 11:42:10 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2018-07-04 15:57:20 +00:00
|
|
|
|
def update_plmn_act(self, mcc, mnc, access_tech='FFFF'):
|
2021-10-29 14:35:22 +00:00
|
|
|
|
"""get size and write EF.PLMNwAcT, See note in update_hplmn_act()"""
|
2019-09-11 23:46:25 +00:00
|
|
|
|
data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
|
2020-02-14 22:03:09 +00:00
|
|
|
|
size = len(data[0]) // 2
|
2018-07-04 15:57:20 +00:00
|
|
|
|
hplmn = enc_plmn(mcc, mnc)
|
|
|
|
|
content = hplmn + access_tech
|
2020-02-26 18:49:51 +00:00
|
|
|
|
data, sw = self._scc.update_binary(EF['PLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
|
2018-07-04 15:57:20 +00:00
|
|
|
|
return sw
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
def update_plmnsel(self, mcc, mnc):
|
|
|
|
|
data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
|
2020-02-14 22:03:09 +00:00
|
|
|
|
size = len(data[0]) // 2
|
2018-07-11 21:23:40 +00:00
|
|
|
|
hplmn = enc_plmn(mcc, mnc)
|
2018-07-13 09:15:49 +00:00
|
|
|
|
data, sw = self._scc.update_binary(EF['PLMNsel'], hplmn + 'ff' * (size-3))
|
|
|
|
|
return sw
|
2018-07-11 21:23:40 +00:00
|
|
|
|
|
2017-07-18 14:04:38 +00:00
|
|
|
|
def update_smsp(self, smsp):
|
|
|
|
|
data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 84))
|
|
|
|
|
return sw
|
|
|
|
|
|
2021-02-24 13:06:18 +00:00
|
|
|
|
def update_ad(self, mnc=None, opmode=None, ofm=None):
|
|
|
|
|
"""
|
|
|
|
|
Update Administrative Data (AD)
|
|
|
|
|
|
|
|
|
|
See Sec. "4.2.18 EF_AD (Administrative Data)"
|
|
|
|
|
in 3GPP TS 31.102 for the details of the EF_AD contents.
|
|
|
|
|
|
|
|
|
|
Set any parameter to None to keep old value(s) on card.
|
2019-03-21 15:21:12 +00:00
|
|
|
|
|
2021-02-24 13:06:18 +00:00
|
|
|
|
Parameters:
|
|
|
|
|
mnc (str): MNC of IMSI
|
|
|
|
|
opmode (Hex-str, 1 Byte): MS Operation Mode
|
|
|
|
|
ofm (Hex-str, 1 Byte): Operational Feature Monitor (OFM) aka Ciphering Indicator
|
2020-05-11 19:28:52 +00:00
|
|
|
|
|
2021-02-24 13:06:18 +00:00
|
|
|
|
Returns:
|
|
|
|
|
str: Return code of write operation
|
|
|
|
|
"""
|
2020-05-11 19:28:52 +00:00
|
|
|
|
|
2021-02-24 13:06:18 +00:00
|
|
|
|
ad = EF_AD()
|
|
|
|
|
|
|
|
|
|
# read from card
|
|
|
|
|
raw_hex_data, sw = self._scc.read_binary(EF['AD'], length=None, offset=0)
|
2021-04-12 09:43:22 +00:00
|
|
|
|
abstract_data = ad.decode_hex(raw_hex_data)
|
2021-02-24 13:06:18 +00:00
|
|
|
|
|
|
|
|
|
# perform updates
|
2021-04-12 09:43:22 +00:00
|
|
|
|
if mnc and abstract_data['extensions']:
|
2021-02-24 13:06:18 +00:00
|
|
|
|
mnclen = len(str(mnc))
|
|
|
|
|
if mnclen == 1:
|
|
|
|
|
mnclen = 2
|
|
|
|
|
if mnclen > 3:
|
|
|
|
|
raise RuntimeError('invalid length of mnc "{}"'.format(mnc))
|
2021-04-12 09:43:22 +00:00
|
|
|
|
abstract_data['extensions']['mnc_len'] = mnclen
|
2021-02-24 13:06:18 +00:00
|
|
|
|
if opmode:
|
2021-04-12 09:43:22 +00:00
|
|
|
|
opmode_num = int(opmode, 16)
|
|
|
|
|
if opmode_num in [int(v) for v in EF_AD.OP_MODE]:
|
|
|
|
|
abstract_data['ms_operation_mode'] = opmode_num
|
2021-02-24 13:06:18 +00:00
|
|
|
|
else:
|
|
|
|
|
raise RuntimeError('invalid opmode "{}"'.format(opmode))
|
|
|
|
|
if ofm:
|
2021-04-12 09:43:22 +00:00
|
|
|
|
abstract_data['ofm'] = bool(int(ofm, 16))
|
2021-02-24 13:06:18 +00:00
|
|
|
|
|
|
|
|
|
# write to card
|
2021-04-12 09:43:22 +00:00
|
|
|
|
raw_hex_data = ad.encode_hex(abstract_data)
|
2021-02-24 13:06:18 +00:00
|
|
|
|
data, sw = self._scc.update_binary(EF['AD'], raw_hex_data)
|
2019-03-21 15:21:12 +00:00
|
|
|
|
return sw
|
|
|
|
|
|
2017-07-18 14:04:38 +00:00
|
|
|
|
def read_spn(self):
|
2021-05-07 13:23:20 +00:00
|
|
|
|
(content, sw) = self._scc.read_binary(EF['SPN'])
|
2017-07-18 14:04:38 +00:00
|
|
|
|
if sw == '9000':
|
2021-05-07 13:23:20 +00:00
|
|
|
|
abstract_data = EF_SPN().decode_hex(content)
|
|
|
|
|
show_in_hplmn = abstract_data['show_in_hplmn']
|
|
|
|
|
hide_in_oplmn = abstract_data['hide_in_oplmn']
|
|
|
|
|
name = abstract_data['spn']
|
|
|
|
|
return ((name, show_in_hplmn, hide_in_oplmn), sw)
|
2017-07-18 14:04:38 +00:00
|
|
|
|
else:
|
|
|
|
|
return (None, sw)
|
|
|
|
|
|
2021-05-07 13:23:20 +00:00
|
|
|
|
def update_spn(self, name="", show_in_hplmn=False, hide_in_oplmn=False):
|
|
|
|
|
abstract_data = {
|
|
|
|
|
'hide_in_oplmn' : hide_in_oplmn,
|
|
|
|
|
'show_in_hplmn' : show_in_hplmn,
|
|
|
|
|
'spn' : name,
|
|
|
|
|
}
|
|
|
|
|
content = EF_SPN().encode_hex(abstract_data)
|
|
|
|
|
data, sw = self._scc.update_binary(EF['SPN'], content)
|
2017-07-18 14:04:38 +00:00
|
|
|
|
return sw
|
|
|
|
|
|
2020-04-01 06:37:47 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-04-01 06:43:08 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-03-18 11:14:48 +00:00
|
|
|
|
def read_gid1(self):
|
|
|
|
|
(res, sw) = self._scc.read_binary(EF['GID1'])
|
|
|
|
|
if sw == '9000':
|
|
|
|
|
return (res, sw)
|
|
|
|
|
else:
|
|
|
|
|
return (None, sw)
|
|
|
|
|
|
2020-03-19 11:49:16 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-03-18 10:33:14 +00:00
|
|
|
|
def read_aids(self):
|
2021-10-29 14:35:22 +00:00
|
|
|
|
"""Fetch all the AIDs present on UICC"""
|
2021-03-10 16:02:53 +00:00
|
|
|
|
self._aids = []
|
2020-03-18 10:33:14 +00:00
|
|
|
|
try:
|
|
|
|
|
# Find out how many records the EF.DIR has
|
|
|
|
|
# and store all the AIDs in the UICC
|
2020-05-28 23:14:55 +00:00
|
|
|
|
rec_cnt = self._scc.record_count(EF['DIR'])
|
2020-03-18 10:33:14 +00:00
|
|
|
|
for i in range(0, rec_cnt):
|
2020-05-28 23:14:55 +00:00
|
|
|
|
rec = self._scc.read_record(EF['DIR'], i + 1)
|
2020-03-18 10:33:14 +00:00
|
|
|
|
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),))
|
2021-03-10 16:02:53 +00:00
|
|
|
|
self._aids = []
|
|
|
|
|
return self._aids
|
2020-03-18 10:33:14 +00:00
|
|
|
|
|
2021-11-16 15:36:50 +00:00
|
|
|
|
@staticmethod
|
|
|
|
|
def _get_aid(adf="usim") -> str:
|
|
|
|
|
aid_map = {}
|
|
|
|
|
# First (known) halves of the U/ISIM AID
|
|
|
|
|
aid_map["usim"] = "a0000000871002"
|
|
|
|
|
aid_map["isim"] = "a0000000871004"
|
|
|
|
|
if adf in aid_map:
|
|
|
|
|
return aid_map[adf]
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def _complete_aid(self, aid) -> str:
|
|
|
|
|
"""find the complete version of an ADF.U/ISIM AID"""
|
|
|
|
|
# Find full AID by partial AID:
|
|
|
|
|
if is_hex(aid):
|
|
|
|
|
for aid_known in self._aids:
|
|
|
|
|
if len(aid_known) >= len(aid) and aid == aid_known[0:len(aid)]:
|
|
|
|
|
return aid_known
|
|
|
|
|
return None
|
|
|
|
|
|
2020-03-22 07:04:59 +00:00
|
|
|
|
def select_adf_by_aid(self, adf="usim"):
|
2021-10-29 14:35:22 +00:00
|
|
|
|
"""Select ADF.U/ISIM in the Card using its full AID"""
|
2021-03-11 12:03:18 +00:00
|
|
|
|
if is_hex(adf):
|
2021-11-16 15:36:50 +00:00
|
|
|
|
aid = adf
|
|
|
|
|
else:
|
|
|
|
|
aid = self._get_aid(adf)
|
|
|
|
|
if aid:
|
|
|
|
|
aid_full = self._complete_aid(aid)
|
|
|
|
|
if aid_full:
|
|
|
|
|
return self._scc.select_adf(aid_full)
|
2021-03-11 12:03:18 +00:00
|
|
|
|
return (None, None)
|
2020-03-22 07:04:59 +00:00
|
|
|
|
|
2020-05-12 14:27:12 +00:00
|
|
|
|
def erase_binary(self, ef):
|
2021-10-29 14:35:22 +00:00
|
|
|
|
"""Erase the contents of a file"""
|
2020-05-12 14:27:12 +00:00
|
|
|
|
len = self._scc.binary_size(ef)
|
|
|
|
|
self._scc.update_binary(ef, "ff" * len, offset=0, verify=True)
|
|
|
|
|
|
|
|
|
|
def erase_record(self, ef, rec_no):
|
2021-10-29 14:35:22 +00:00
|
|
|
|
"""Erase the contents of a single record"""
|
2020-05-12 14:27:12 +00:00
|
|
|
|
len = self._scc.record_size(ef)
|
|
|
|
|
self._scc.update_record(ef, rec_no, "ff" * len, force_len=False, verify=True)
|
|
|
|
|
|
2021-10-29 14:41:46 +00:00
|
|
|
|
def set_apdu_parameter(self, cla, sel_ctrl):
|
|
|
|
|
"""Set apdu parameters (class byte and selection control bytes)"""
|
|
|
|
|
self._scc.cla_byte = cla
|
|
|
|
|
self._scc.sel_ctrl = sel_ctrl
|
|
|
|
|
|
|
|
|
|
def get_apdu_parameter(self):
|
|
|
|
|
"""Get apdu parameters (class byte and selection control bytes)"""
|
|
|
|
|
return (self._scc.cla_byte, self._scc.sel_ctrl)
|
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class UsimCard(SimCard):
|
2021-05-05 10:18:41 +00:00
|
|
|
|
|
|
|
|
|
name = 'USIM'
|
|
|
|
|
|
2020-06-03 13:19:40 +00:00
|
|
|
|
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
|
|
|
|
|
|
2020-09-29 08:03:06 +00:00
|
|
|
|
def read_epdgid(self):
|
|
|
|
|
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
|
|
|
|
|
if sw == '9000':
|
2021-04-30 13:00:27 +00:00
|
|
|
|
try:
|
|
|
|
|
addr, addr_type = dec_addr_tlv(res)
|
|
|
|
|
except:
|
|
|
|
|
addr = None
|
|
|
|
|
addr_type = None
|
|
|
|
|
return (format_addr(addr, addr_type), sw)
|
2020-09-29 08:03:06 +00:00
|
|
|
|
else:
|
|
|
|
|
return (None, sw)
|
|
|
|
|
|
2020-09-29 07:44:24 +00:00
|
|
|
|
def update_epdgid(self, epdgid):
|
2020-03-25 11:51:38 +00:00
|
|
|
|
size = self._scc.binary_size(EF_USIM_ADF_map['ePDGId']) * 2
|
|
|
|
|
if len(epdgid) > 0:
|
2020-03-25 13:56:13 +00:00
|
|
|
|
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)
|
2020-03-25 11:51:38 +00:00
|
|
|
|
else:
|
|
|
|
|
epdgid_tlv = rpad('ff', size)
|
2020-09-29 07:44:24 +00:00
|
|
|
|
data, sw = self._scc.update_binary(
|
|
|
|
|
EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
|
|
|
|
|
return sw
|
2020-06-03 13:19:40 +00:00
|
|
|
|
|
2020-03-24 12:03:43 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-03-24 12:15:37 +00:00
|
|
|
|
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
|
|
|
|
|
|
2020-09-29 08:11:36 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-03-24 12:26:53 +00:00
|
|
|
|
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
|
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class IsimCard(SimCard):
|
2021-05-05 10:18:41 +00:00
|
|
|
|
|
|
|
|
|
name = 'ISIM'
|
|
|
|
|
|
2020-12-23 08:24:29 +00:00
|
|
|
|
def __init__(self, ssc):
|
|
|
|
|
super(IsimCard, self).__init__(ssc)
|
|
|
|
|
|
2020-03-24 16:26:40 +00:00
|
|
|
|
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':
|
2021-04-30 13:00:27 +00:00
|
|
|
|
try:
|
|
|
|
|
addr, addr_type = dec_addr_tlv(res)
|
|
|
|
|
except:
|
|
|
|
|
addr = None
|
|
|
|
|
addr_type = None
|
|
|
|
|
content = format_addr(addr, addr_type)
|
2020-03-24 16:26:40 +00:00
|
|
|
|
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
|
|
|
|
|
|
2020-03-24 16:32:21 +00:00
|
|
|
|
def update_pcscf(self, pcscf):
|
|
|
|
|
if len(pcscf) > 0:
|
2020-12-24 08:38:42 +00:00
|
|
|
|
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))
|
2020-03-24 16:32:21 +00:00
|
|
|
|
else:
|
|
|
|
|
# Just the tag value
|
|
|
|
|
content = '80'
|
|
|
|
|
rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['PCSCF'])
|
2020-12-24 08:38:42 +00:00
|
|
|
|
pcscf_tlv = rpad(content, rec_size_bytes*2)
|
|
|
|
|
data, sw = self._scc.update_record(EF_ISIM_ADF_map['PCSCF'], 1, pcscf_tlv)
|
2020-03-24 16:32:21 +00:00
|
|
|
|
return sw
|
|
|
|
|
|
2020-03-25 09:23:48 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-03-25 10:43:19 +00:00
|
|
|
|
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
|
|
|
|
|
|
2020-03-25 14:38:02 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-03-26 08:16:14 +00:00
|
|
|
|
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
|
|
|
|
|
|
2020-03-26 08:00:06 +00:00
|
|
|
|
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
|
|
|
|
|
|
2020-03-26 08:27:45 +00:00
|
|
|
|
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
|
|
|
|
|
|
2020-06-01 10:53:57 +00:00
|
|
|
|
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
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class MagicSimBase(abc.ABC, SimCard):
|
2010-12-06 23:24:32 +00:00
|
|
|
|
"""
|
|
|
|
|
Theses cards uses several record based EFs to store the provider infos,
|
|
|
|
|
each possible provider uses a specific record number in each EF. The
|
|
|
|
|
indexes used are ( where N is the number of providers supported ) :
|
|
|
|
|
- [2 .. N+1] for the operator name
|
2021-04-11 08:28:28 +00:00
|
|
|
|
- [1 .. N] for the programmable EFs
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
* 3f00/7f4d/8f0c : Operator Name
|
|
|
|
|
|
|
|
|
|
bytes 0-15 : provider name, padded with 0xff
|
|
|
|
|
byte 16 : length of the provider name
|
|
|
|
|
byte 17 : 01 for valid records, 00 otherwise
|
|
|
|
|
|
|
|
|
|
* 3f00/7f4d/8f0d : Programmable Binary EFs
|
|
|
|
|
|
|
|
|
|
* 3f00/7f4d/8f0e : Programmable Record EFs
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
2021-05-02 00:10:39 +00:00
|
|
|
|
_files = { } # type: Dict[str, Tuple[str, int, bool]]
|
|
|
|
|
_ki_file = None # type: Optional[str]
|
|
|
|
|
|
2010-12-06 23:24:32 +00:00
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
try:
|
|
|
|
|
for p, l, t in kls._files.values():
|
|
|
|
|
if not t:
|
|
|
|
|
continue
|
|
|
|
|
if scc.record_size(['3f00', '7f4d', p]) != l:
|
|
|
|
|
return None
|
|
|
|
|
except:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
return kls(scc)
|
|
|
|
|
|
|
|
|
|
def _get_count(self):
|
|
|
|
|
"""
|
|
|
|
|
Selects the file and returns the total number of entries
|
|
|
|
|
and entry size
|
|
|
|
|
"""
|
|
|
|
|
f = self._files['name']
|
|
|
|
|
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f4d', f[0]])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
rec_len = int(r[-1][28:30], 16)
|
|
|
|
|
tlen = int(r[-1][4:8],16)
|
2021-05-02 00:23:48 +00:00
|
|
|
|
rec_cnt = (tlen // rec_len) - 1
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
if (rec_cnt < 1) or (rec_len != f[1]):
|
|
|
|
|
raise RuntimeError('Bad card type')
|
|
|
|
|
|
|
|
|
|
return rec_cnt
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
# Go to dir
|
2021-01-21 15:06:50 +00:00
|
|
|
|
self._scc.select_path(['3f00', '7f4d'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
# Home PLMN in PLMN_Sel format
|
2013-07-10 07:18:06 +00:00
|
|
|
|
hplmn = enc_plmn(p['mcc'], p['mnc'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
# Operator name ( 3f00/7f4d/8f0c )
|
|
|
|
|
self._scc.update_record(self._files['name'][0], 2,
|
|
|
|
|
rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01'
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
|
|
|
|
|
v = ''
|
|
|
|
|
|
|
|
|
|
# inline Ki
|
|
|
|
|
if self._ki_file is None:
|
|
|
|
|
v += p['ki']
|
|
|
|
|
|
|
|
|
|
# ICCID
|
2013-07-10 07:18:06 +00:00
|
|
|
|
v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
# IMSI
|
2013-07-10 07:18:06 +00:00
|
|
|
|
v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
# Ki
|
|
|
|
|
if self._ki_file:
|
|
|
|
|
v += self._ki_file + '10' + p['ki']
|
|
|
|
|
|
|
|
|
|
# PLMN_Sel
|
|
|
|
|
v+= '6f30' + '18' + rpad(hplmn, 36)
|
|
|
|
|
|
2013-07-02 12:56:55 +00:00
|
|
|
|
# ACC
|
|
|
|
|
# This doesn't work with "fake" SuperSIM cards,
|
|
|
|
|
# but will hopefully work with real SuperSIMs.
|
|
|
|
|
if p.get('acc') is not None:
|
|
|
|
|
v+= '6f78' + '02' + lpad(p['acc'], 4)
|
|
|
|
|
|
2010-12-06 23:24:32 +00:00
|
|
|
|
self._scc.update_record(self._files['b_ef'][0], 1,
|
|
|
|
|
rpad(v, self._files['b_ef'][1]*2)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# SMSP ( 3f00/7f4d/8f0e )
|
|
|
|
|
# FIXME
|
|
|
|
|
|
|
|
|
|
# Write PLMN_Sel forcefully as well
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f20', '6f30'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
tl = int(r[-1][4:8], 16)
|
|
|
|
|
|
2013-07-10 07:18:06 +00:00
|
|
|
|
hplmn = enc_plmn(p['mcc'], p['mnc'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
|
|
|
|
|
|
|
|
|
|
def erase(self):
|
|
|
|
|
# Dummy
|
|
|
|
|
df = {}
|
2021-05-02 00:12:47 +00:00
|
|
|
|
for k, v in self._files.items():
|
2010-12-06 23:24:32 +00:00
|
|
|
|
ofs = 1
|
|
|
|
|
fv = v[1] * 'ff'
|
|
|
|
|
if k == 'name':
|
|
|
|
|
ofs = 2
|
|
|
|
|
fv = fv[0:-4] + '0000'
|
|
|
|
|
df[v[0]] = (fv, ofs)
|
|
|
|
|
|
|
|
|
|
# Write
|
|
|
|
|
for n in range(0,self._get_count()):
|
2021-05-02 00:12:47 +00:00
|
|
|
|
for k, (msg, ofs) in df.items():
|
2010-12-06 23:24:32 +00:00
|
|
|
|
self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
|
|
|
|
|
|
|
|
|
|
|
2021-05-02 00:18:42 +00:00
|
|
|
|
class SuperSim(MagicSimBase):
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
name = 'supersim'
|
|
|
|
|
|
|
|
|
|
_files = {
|
|
|
|
|
'name' : ('8f0c', 18, True),
|
|
|
|
|
'b_ef' : ('8f0d', 74, True),
|
|
|
|
|
'r_ef' : ('8f0e', 50, True),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ki_file = None
|
|
|
|
|
|
|
|
|
|
|
2021-05-02 00:18:42 +00:00
|
|
|
|
class MagicSim(MagicSimBase):
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
name = 'magicsim'
|
|
|
|
|
|
|
|
|
|
_files = {
|
|
|
|
|
'name' : ('8f0c', 18, True),
|
|
|
|
|
'b_ef' : ('8f0d', 130, True),
|
|
|
|
|
'r_ef' : ('8f0e', 102, False),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ki_file = '6f1b'
|
|
|
|
|
|
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class FakeMagicSim(SimCard):
|
2010-12-06 23:24:32 +00:00
|
|
|
|
"""
|
|
|
|
|
Theses cards have a record based EF 3f00/000c that contains the provider
|
2021-04-11 08:28:28 +00:00
|
|
|
|
information. See the program method for its format. The records go from
|
2010-12-06 23:24:32 +00:00
|
|
|
|
1 to N.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
name = 'fakemagicsim'
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
try:
|
|
|
|
|
if scc.record_size(['3f00', '000c']) != 0x5a:
|
|
|
|
|
return None
|
|
|
|
|
except:
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
return kls(scc)
|
|
|
|
|
|
|
|
|
|
def _get_infos(self):
|
|
|
|
|
"""
|
|
|
|
|
Selects the file and returns the total number of entries
|
|
|
|
|
and entry size
|
|
|
|
|
"""
|
|
|
|
|
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '000c'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
rec_len = int(r[-1][28:30], 16)
|
|
|
|
|
tlen = int(r[-1][4:8],16)
|
2021-05-02 00:23:48 +00:00
|
|
|
|
rec_cnt = (tlen // rec_len) - 1
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
|
|
|
|
if (rec_cnt < 1) or (rec_len != 0x5a):
|
|
|
|
|
raise RuntimeError('Bad card type')
|
|
|
|
|
|
|
|
|
|
return rec_cnt, rec_len
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
# Home PLMN
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f20', '6f30'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
tl = int(r[-1][4:8], 16)
|
|
|
|
|
|
2013-07-10 07:18:06 +00:00
|
|
|
|
hplmn = enc_plmn(p['mcc'], p['mnc'])
|
2010-12-06 23:24:32 +00:00
|
|
|
|
self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
|
|
|
|
|
|
|
|
|
|
# Get total number of entries and entry size
|
|
|
|
|
rec_cnt, rec_len = self._get_infos()
|
|
|
|
|
|
|
|
|
|
# Set first entry
|
|
|
|
|
entry = (
|
2019-04-01 13:49:45 +00:00
|
|
|
|
'81' + # 1b Status: Valid & Active
|
2021-02-01 16:51:56 +00:00
|
|
|
|
rpad(s2h(p['name'][0:14]), 28) + # 14b Entry Name
|
2019-04-01 13:49:45 +00:00
|
|
|
|
enc_iccid(p['iccid']) + # 10b ICCID
|
|
|
|
|
enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
|
|
|
|
|
p['ki'] + # 16b Ki
|
|
|
|
|
lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
|
2010-12-06 23:24:32 +00:00
|
|
|
|
)
|
|
|
|
|
self._scc.update_record('000c', 1, entry)
|
|
|
|
|
|
|
|
|
|
def erase(self):
|
|
|
|
|
# Get total number of entries and entry size
|
|
|
|
|
rec_cnt, rec_len = self._get_infos()
|
|
|
|
|
|
|
|
|
|
# Erase all entries
|
|
|
|
|
entry = 'ff' * rec_len
|
|
|
|
|
for i in range(0, rec_cnt):
|
|
|
|
|
self._scc.update_record('000c', 1+i, entry)
|
|
|
|
|
|
2013-07-02 13:13:24 +00:00
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class GrcardSim(SimCard):
|
2011-03-22 20:48:19 +00:00
|
|
|
|
"""
|
|
|
|
|
Greencard (grcard.cn) HZCOS GSM SIM
|
|
|
|
|
These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
|
|
|
|
|
and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
name = 'grcardsim'
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
# We don't really know yet what ADM PIN 4 is about
|
|
|
|
|
#self._scc.verify_chv(4, h2b("4444444444444444"))
|
|
|
|
|
|
|
|
|
|
# Authenticate using ADM PIN 5
|
2015-01-26 11:22:55 +00:00
|
|
|
|
if p['pin_adm']:
|
2018-08-23 08:27:04 +00:00
|
|
|
|
pin = h2b(p['pin_adm'])
|
2015-01-26 11:22:55 +00:00
|
|
|
|
else:
|
|
|
|
|
pin = h2b("4444444444444444")
|
|
|
|
|
self._scc.verify_chv(5, pin)
|
2011-03-22 20:48:19 +00:00
|
|
|
|
|
|
|
|
|
# EF.ICCID
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '2fe2'])
|
2013-07-10 07:18:06 +00:00
|
|
|
|
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
|
2011-03-22 20:48:19 +00:00
|
|
|
|
|
|
|
|
|
# EF.IMSI
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f20', '6f07'])
|
2013-07-10 07:18:06 +00:00
|
|
|
|
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
2011-03-22 20:48:19 +00:00
|
|
|
|
|
|
|
|
|
# EF.ACC
|
2013-07-02 12:56:55 +00:00
|
|
|
|
if p.get('acc') is not None:
|
|
|
|
|
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
|
2011-03-22 20:48:19 +00:00
|
|
|
|
|
|
|
|
|
# EF.SMSP
|
2019-09-11 23:46:25 +00:00
|
|
|
|
if p.get('smsp'):
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f10', '6f42'])
|
2019-08-28 21:19:11 +00:00
|
|
|
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
2011-03-22 20:48:19 +00:00
|
|
|
|
|
|
|
|
|
# Set the Ki using proprietary command
|
|
|
|
|
pdu = '80d4020010' + p['ki']
|
|
|
|
|
data, sw = self._scc._tp.send_apdu(pdu)
|
|
|
|
|
|
|
|
|
|
# EF.HPLMN
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f20', '6f30'])
|
2011-03-22 20:48:19 +00:00
|
|
|
|
size = int(r[-1][4:8], 16)
|
2013-07-10 07:18:06 +00:00
|
|
|
|
hplmn = enc_plmn(p['mcc'], p['mnc'])
|
2011-03-22 20:48:19 +00:00
|
|
|
|
self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
|
|
|
|
|
|
|
|
|
|
# EF.SPN (Service Provider Name)
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f20', '6f30'])
|
2011-03-22 20:48:19 +00:00
|
|
|
|
size = int(r[-1][4:8], 16)
|
|
|
|
|
# FIXME
|
|
|
|
|
|
|
|
|
|
# FIXME: EF.MSISDN
|
|
|
|
|
|
2010-12-06 23:24:32 +00:00
|
|
|
|
|
2011-12-07 11:34:14 +00:00
|
|
|
|
class SysmoSIMgr1(GrcardSim):
|
|
|
|
|
"""
|
|
|
|
|
sysmocom sysmoSIM-GR1
|
|
|
|
|
These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
|
|
|
|
|
and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
|
|
|
|
|
"""
|
|
|
|
|
name = 'sysmosim-gr1'
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
@classmethod
|
2018-08-23 07:41:36 +00:00
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
try:
|
|
|
|
|
# Look for ATR
|
|
|
|
|
if scc.get_atr() == toBytes("3B 99 18 00 11 88 22 33 44 55 66 77 60"):
|
|
|
|
|
return kls(scc)
|
|
|
|
|
except:
|
|
|
|
|
return None
|
|
|
|
|
return None
|
2013-07-02 13:13:24 +00:00
|
|
|
|
|
2020-06-03 13:19:40 +00:00
|
|
|
|
class SysmoUSIMgr1(UsimCard):
|
2012-03-22 13:28:38 +00:00
|
|
|
|
"""
|
|
|
|
|
sysmocom sysmoUSIM-GR1
|
|
|
|
|
"""
|
|
|
|
|
name = 'sysmoUSIM-GR1'
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
# TODO: Access the ATR
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
# TODO: check if verify_chv could be used or what it needs
|
|
|
|
|
# self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
|
|
|
|
|
# Unlock the card..
|
|
|
|
|
data, sw = self._scc._tp.send_apdu_checksw("0020000A083332323133323332")
|
|
|
|
|
|
|
|
|
|
# TODO: move into SimCardCommands
|
|
|
|
|
par = ( p['ki'] + # 16b K
|
2013-07-10 07:18:06 +00:00
|
|
|
|
p['opc'] + # 32b OPC
|
|
|
|
|
enc_iccid(p['iccid']) + # 10b ICCID
|
|
|
|
|
enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
|
2012-03-22 13:28:38 +00:00
|
|
|
|
)
|
|
|
|
|
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
|
|
|
|
|
|
2013-07-02 13:12:32 +00:00
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class SysmoSIMgr2(SimCard):
|
2013-12-23 16:22:56 +00:00
|
|
|
|
"""
|
|
|
|
|
sysmocom sysmoSIM-GR2
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
name = 'sysmoSIM-GR2'
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
2018-01-10 05:17:55 +00:00
|
|
|
|
try:
|
|
|
|
|
# Look for ATR
|
|
|
|
|
if scc.get_atr() == toBytes("3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68"):
|
|
|
|
|
return kls(scc)
|
|
|
|
|
except:
|
|
|
|
|
return None
|
2013-12-23 16:22:56 +00:00
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
|
2020-10-19 09:01:49 +00:00
|
|
|
|
# select MF
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00'])
|
2020-10-19 09:01:49 +00:00
|
|
|
|
|
2013-12-23 16:22:56 +00:00
|
|
|
|
# authenticate as SUPER ADM using default key
|
|
|
|
|
self._scc.verify_chv(0x0b, h2b("3838383838383838"))
|
|
|
|
|
|
|
|
|
|
# set ADM pin using proprietary command
|
|
|
|
|
# INS: D4
|
|
|
|
|
# P1: 3A for PIN, 3B for PUK
|
|
|
|
|
# P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
|
|
|
|
|
# P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
|
2015-01-26 11:22:55 +00:00
|
|
|
|
if p['pin_adm']:
|
2018-06-15 05:31:50 +00:00
|
|
|
|
pin = h2b(p['pin_adm'])
|
2015-01-26 11:22:55 +00:00
|
|
|
|
else:
|
|
|
|
|
pin = h2b("4444444444444444")
|
|
|
|
|
|
|
|
|
|
pdu = 'A0D43A0508' + b2h(pin)
|
2013-12-23 16:22:56 +00:00
|
|
|
|
data, sw = self._scc._tp.send_apdu(pdu)
|
2020-10-19 09:01:49 +00:00
|
|
|
|
|
2013-12-23 16:22:56 +00:00
|
|
|
|
# authenticate as ADM (enough to write file, and can set PINs)
|
2015-01-26 11:22:55 +00:00
|
|
|
|
|
|
|
|
|
self._scc.verify_chv(0x05, pin)
|
2013-12-23 16:22:56 +00:00
|
|
|
|
|
|
|
|
|
# write EF.ICCID
|
|
|
|
|
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
|
|
|
|
|
|
|
|
|
|
# select DF_GSM
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['7f20'])
|
2020-10-19 09:01:49 +00:00
|
|
|
|
|
2013-12-23 16:22:56 +00:00
|
|
|
|
# write EF.IMSI
|
|
|
|
|
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
|
|
|
|
|
|
|
|
|
# write EF.ACC
|
|
|
|
|
if p.get('acc') is not None:
|
|
|
|
|
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
|
|
|
|
|
|
|
|
|
|
# get size and write EF.HPLMN
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['6f30'])
|
2013-12-23 16:22:56 +00:00
|
|
|
|
size = int(r[-1][4:8], 16)
|
|
|
|
|
hplmn = enc_plmn(p['mcc'], p['mnc'])
|
|
|
|
|
self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
|
|
|
|
|
|
|
|
|
|
# set COMP128 version 0 in proprietary file
|
|
|
|
|
data, sw = self._scc.update_binary('0001', '001000')
|
|
|
|
|
|
|
|
|
|
# set Ki in proprietary file
|
|
|
|
|
data, sw = self._scc.update_binary('0001', p['ki'], 3)
|
|
|
|
|
|
|
|
|
|
# select DF_TELECOM
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f10'])
|
2020-10-19 09:01:49 +00:00
|
|
|
|
|
2013-12-23 16:22:56 +00:00
|
|
|
|
# write EF.SMSP
|
2019-09-11 23:46:25 +00:00
|
|
|
|
if p.get('smsp'):
|
2019-08-28 21:19:11 +00:00
|
|
|
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
|
2013-12-23 16:22:56 +00:00
|
|
|
|
|
|
|
|
|
|
2020-06-03 13:19:40 +00:00
|
|
|
|
class SysmoUSIMSJS1(UsimCard):
|
2015-01-26 14:36:27 +00:00
|
|
|
|
"""
|
|
|
|
|
sysmocom sysmoUSIM-SJS1
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
name = 'sysmoUSIM-SJS1'
|
|
|
|
|
|
|
|
|
|
def __init__(self, ssc):
|
|
|
|
|
super(SysmoUSIMSJS1, self).__init__(ssc)
|
|
|
|
|
self._scc.cla_byte = "00"
|
2019-03-20 11:40:36 +00:00
|
|
|
|
self._scc.sel_ctrl = "0004" #request an FCP
|
2015-01-26 14:36:27 +00:00
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
2018-01-10 05:17:55 +00:00
|
|
|
|
try:
|
|
|
|
|
# Look for ATR
|
|
|
|
|
if scc.get_atr() == toBytes("3B 9F 96 80 1F C7 80 31 A0 73 BE 21 13 67 43 20 07 18 00 00 01 A5"):
|
|
|
|
|
return kls(scc)
|
|
|
|
|
except:
|
|
|
|
|
return None
|
2015-01-26 14:36:27 +00:00
|
|
|
|
return None
|
|
|
|
|
|
2021-01-08 19:19:11 +00:00
|
|
|
|
def verify_adm(self, key):
|
2017-03-21 16:24:31 +00:00
|
|
|
|
# authenticate as ADM using default key (written on the card..)
|
2021-01-08 19:19:11 +00:00
|
|
|
|
if not key:
|
2017-03-21 16:24:31 +00:00
|
|
|
|
raise ValueError("Please provide a PIN-ADM as there is no default one")
|
2021-01-08 19:19:11 +00:00
|
|
|
|
(res, sw) = self._scc.verify_chv(0x0A, key)
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
self.verify_adm(h2b(p['pin_adm']))
|
2015-01-26 14:36:27 +00:00
|
|
|
|
|
|
|
|
|
# select MF
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00'])
|
2015-01-26 14:36:27 +00:00
|
|
|
|
|
2017-03-21 16:24:31 +00:00
|
|
|
|
# write EF.ICCID
|
|
|
|
|
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
|
|
|
|
|
|
2015-01-26 14:36:27 +00:00
|
|
|
|
# select DF_GSM
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['7f20'])
|
2015-01-26 14:36:27 +00:00
|
|
|
|
|
|
|
|
|
# set Ki in proprietary file
|
|
|
|
|
data, sw = self._scc.update_binary('00FF', p['ki'])
|
|
|
|
|
|
2018-07-13 09:29:03 +00:00
|
|
|
|
# set OPc in proprietary file
|
2018-06-15 05:42:48 +00:00
|
|
|
|
if 'opc' in p:
|
|
|
|
|
content = "01" + p['opc']
|
|
|
|
|
data, sw = self._scc.update_binary('00F7', content)
|
2015-01-26 14:36:27 +00:00
|
|
|
|
|
2019-06-08 05:50:53 +00:00
|
|
|
|
# set Service Provider Name
|
2020-01-21 12:32:46 +00:00
|
|
|
|
if p.get('name') is not None:
|
2021-05-07 13:23:20 +00:00
|
|
|
|
self.update_spn(p['name'], True, True)
|
2019-06-08 05:50:53 +00:00
|
|
|
|
|
2019-12-23 11:23:42 +00:00
|
|
|
|
if p.get('acc') is not None:
|
|
|
|
|
self.update_acc(p['acc'])
|
|
|
|
|
|
2015-01-26 14:36:27 +00:00
|
|
|
|
# write EF.IMSI
|
|
|
|
|
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
|
|
|
|
|
2019-03-20 11:40:36 +00:00
|
|
|
|
# EF.PLMNsel
|
2019-09-11 23:46:25 +00:00
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
|
|
|
|
sw = self.update_plmnsel(p['mcc'], p['mnc'])
|
|
|
|
|
if sw != '9000':
|
2019-03-20 11:40:36 +00:00
|
|
|
|
print("Programming PLMNsel failed with code %s"%sw)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.PLMNwAcT
|
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
2019-03-20 11:40:36 +00:00
|
|
|
|
sw = self.update_plmn_act(p['mcc'], p['mnc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming PLMNwAcT failed with code %s"%sw)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.OPLMNwAcT
|
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
2019-03-20 11:40:36 +00:00
|
|
|
|
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming OPLMNwAcT failed with code %s"%sw)
|
|
|
|
|
|
2020-01-21 11:47:32 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.AD
|
2021-02-24 13:06:18 +00:00
|
|
|
|
if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
|
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
|
|
|
|
mnc = p['mnc']
|
|
|
|
|
else:
|
|
|
|
|
mnc = None
|
|
|
|
|
sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
|
2019-03-21 15:21:12 +00:00
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming AD failed with code %s"%sw)
|
2019-03-20 11:40:36 +00:00
|
|
|
|
|
2017-08-31 08:08:45 +00:00
|
|
|
|
# EF.SMSP
|
2019-08-28 21:19:11 +00:00
|
|
|
|
if p.get('smsp'):
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f10'])
|
2019-08-28 21:19:11 +00:00
|
|
|
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
|
2015-01-26 14:36:27 +00:00
|
|
|
|
|
2019-12-22 07:59:16 +00:00
|
|
|
|
# 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'])
|
2021-04-20 20:38:21 +00:00
|
|
|
|
data = 'ff' * 20 + msisdn
|
2019-12-22 07:59:16 +00:00
|
|
|
|
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f10'])
|
2019-12-22 07:59:16 +00:00
|
|
|
|
data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
|
|
|
|
|
|
2015-01-26 14:36:27 +00:00
|
|
|
|
|
2020-09-29 08:11:36 +00:00
|
|
|
|
class FairwavesSIM(UsimCard):
|
2018-01-10 05:18:32 +00:00
|
|
|
|
"""
|
|
|
|
|
FairwavesSIM
|
|
|
|
|
|
|
|
|
|
The SIM card is operating according to the standard.
|
|
|
|
|
For Ki/OP/OPC programming the following files are additionally open for writing:
|
|
|
|
|
3F00/7F20/FF01 – OP/OPC:
|
|
|
|
|
byte 1 = 0x01, bytes 2-17: OPC;
|
|
|
|
|
byte 1 = 0x00, bytes 2-17: OP;
|
|
|
|
|
3F00/7F20/FF02: Ki
|
|
|
|
|
"""
|
|
|
|
|
|
2019-11-11 10:01:46 +00:00
|
|
|
|
name = 'Fairwaves-SIM'
|
2018-01-10 05:18:32 +00:00
|
|
|
|
# Propriatary files
|
|
|
|
|
_EF_num = {
|
|
|
|
|
'Ki': 'FF02',
|
|
|
|
|
'OP/OPC': 'FF01',
|
|
|
|
|
}
|
|
|
|
|
_EF = {
|
|
|
|
|
'Ki': DF['GSM']+[_EF_num['Ki']],
|
|
|
|
|
'OP/OPC': DF['GSM']+[_EF_num['OP/OPC']],
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
def __init__(self, ssc):
|
|
|
|
|
super(FairwavesSIM, self).__init__(ssc)
|
|
|
|
|
self._adm_chv_num = 0x11
|
|
|
|
|
self._adm2_chv_num = 0x12
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
try:
|
|
|
|
|
# Look for ATR
|
|
|
|
|
if scc.get_atr() == toBytes("3B 9F 96 80 1F C7 80 31 A0 73 BE 21 13 67 44 22 06 10 00 00 01 A9"):
|
|
|
|
|
return kls(scc)
|
|
|
|
|
except:
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def verify_adm2(self, key):
|
|
|
|
|
'''
|
|
|
|
|
Authenticate with ADM2 key.
|
|
|
|
|
|
|
|
|
|
Fairwaves SIM cards support hierarchical key structure and ADM2 key
|
|
|
|
|
is a key which has access to proprietary files (Ki and OP/OPC).
|
|
|
|
|
That said, ADM key inherits permissions of ADM2 key and thus we rarely
|
|
|
|
|
need ADM2 key per se.
|
|
|
|
|
'''
|
|
|
|
|
(res, sw) = self._scc.verify_chv(self._adm2_chv_num, key)
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def read_ki(self):
|
|
|
|
|
"""
|
|
|
|
|
Read Ki in proprietary file.
|
|
|
|
|
|
|
|
|
|
Requires ADM1 access level
|
|
|
|
|
"""
|
|
|
|
|
return self._scc.read_binary(self._EF['Ki'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_ki(self, ki):
|
|
|
|
|
"""
|
|
|
|
|
Set Ki in proprietary file.
|
|
|
|
|
|
|
|
|
|
Requires ADM1 access level
|
|
|
|
|
"""
|
|
|
|
|
data, sw = self._scc.update_binary(self._EF['Ki'], ki)
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def read_op_opc(self):
|
|
|
|
|
"""
|
|
|
|
|
Read Ki in proprietary file.
|
|
|
|
|
|
|
|
|
|
Requires ADM1 access level
|
|
|
|
|
"""
|
|
|
|
|
(ef, sw) = self._scc.read_binary(self._EF['OP/OPC'])
|
|
|
|
|
type = 'OP' if ef[0:2] == '00' else 'OPC'
|
|
|
|
|
return ((type, ef[2:]), sw)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_op(self, op):
|
|
|
|
|
"""
|
|
|
|
|
Set OP in proprietary file.
|
|
|
|
|
|
|
|
|
|
Requires ADM1 access level
|
|
|
|
|
"""
|
|
|
|
|
content = '00' + op
|
|
|
|
|
data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def update_opc(self, opc):
|
|
|
|
|
"""
|
|
|
|
|
Set OPC in proprietary file.
|
|
|
|
|
|
|
|
|
|
Requires ADM1 access level
|
|
|
|
|
"""
|
|
|
|
|
content = '01' + opc
|
|
|
|
|
data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
2021-10-05 11:58:25 +00:00
|
|
|
|
# For some reason the card programming only works when the card
|
|
|
|
|
# is handled as a classic SIM, even though it is an USIM, so we
|
|
|
|
|
# reconfigure the class byte and the select control field on
|
|
|
|
|
# the fly. When the programming is done the original values are
|
|
|
|
|
# restored.
|
|
|
|
|
cla_byte_orig = self._scc.cla_byte
|
|
|
|
|
sel_ctrl_orig = self._scc.sel_ctrl
|
|
|
|
|
self._scc.cla_byte = "a0"
|
|
|
|
|
self._scc.sel_ctrl = "0000"
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
self._program(p)
|
|
|
|
|
finally:
|
|
|
|
|
# restore original cla byte and sel ctrl
|
|
|
|
|
self._scc.cla_byte = cla_byte_orig
|
|
|
|
|
self._scc.sel_ctrl = sel_ctrl_orig
|
|
|
|
|
|
|
|
|
|
def _program(self, p):
|
2018-01-10 05:18:32 +00:00
|
|
|
|
# authenticate as ADM1
|
|
|
|
|
if not p['pin_adm']:
|
|
|
|
|
raise ValueError("Please provide a PIN-ADM as there is no default one")
|
2021-03-11 12:59:44 +00:00
|
|
|
|
self.verify_adm(h2b(p['pin_adm']))
|
2018-01-10 05:18:32 +00:00
|
|
|
|
|
|
|
|
|
# TODO: Set operator name
|
|
|
|
|
if p.get('smsp') is not None:
|
|
|
|
|
sw = self.update_smsp(p['smsp'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming SMSP failed with code %s"%sw)
|
|
|
|
|
# This SIM doesn't support changing ICCID
|
|
|
|
|
if p.get('mcc') is not None and p.get('mnc') is not None:
|
|
|
|
|
sw = self.update_hplmn_act(p['mcc'], p['mnc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming MCC/MNC failed with code %s"%sw)
|
|
|
|
|
if p.get('imsi') is not None:
|
|
|
|
|
sw = self.update_imsi(p['imsi'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming IMSI failed with code %s"%sw)
|
|
|
|
|
if p.get('ki') is not None:
|
|
|
|
|
sw = self.update_ki(p['ki'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming Ki failed with code %s"%sw)
|
|
|
|
|
if p.get('opc') is not None:
|
|
|
|
|
sw = self.update_opc(p['opc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming OPC failed with code %s"%sw)
|
|
|
|
|
if p.get('acc') is not None:
|
|
|
|
|
sw = self.update_acc(p['acc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming ACC failed with code %s"%sw)
|
|
|
|
|
|
2021-05-05 14:14:00 +00:00
|
|
|
|
class OpenCellsSim(SimCard):
|
2018-04-25 20:36:29 +00:00
|
|
|
|
"""
|
|
|
|
|
OpenCellsSim
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
2019-11-11 10:01:46 +00:00
|
|
|
|
name = 'OpenCells-SIM'
|
2018-04-25 20:36:29 +00:00
|
|
|
|
|
|
|
|
|
def __init__(self, ssc):
|
|
|
|
|
super(OpenCellsSim, self).__init__(ssc)
|
|
|
|
|
self._adm_chv_num = 0x0A
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
try:
|
|
|
|
|
# Look for ATR
|
|
|
|
|
if scc.get_atr() == toBytes("3B 9F 95 80 1F C3 80 31 E0 73 FE 21 13 57 86 81 02 86 98 44 18 A8"):
|
|
|
|
|
return kls(scc)
|
|
|
|
|
except:
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
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']))
|
|
|
|
|
|
|
|
|
|
# select MF
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00'])
|
2018-04-25 20:36:29 +00:00
|
|
|
|
|
|
|
|
|
# write EF.ICCID
|
|
|
|
|
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
|
|
|
|
|
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['7ff0'])
|
2018-04-25 20:36:29 +00:00
|
|
|
|
|
|
|
|
|
# set Ki in proprietary file
|
|
|
|
|
data, sw = self._scc.update_binary('FF02', p['ki'])
|
|
|
|
|
|
|
|
|
|
# set OPC in proprietary file
|
|
|
|
|
data, sw = self._scc.update_binary('FF01', p['opc'])
|
|
|
|
|
|
|
|
|
|
# select DF_GSM
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['7f20'])
|
2018-04-25 20:36:29 +00:00
|
|
|
|
|
|
|
|
|
# write EF.IMSI
|
|
|
|
|
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
|
|
|
|
|
|
2020-09-29 08:11:36 +00:00
|
|
|
|
class WavemobileSim(UsimCard):
|
2018-07-04 15:57:20 +00:00
|
|
|
|
"""
|
|
|
|
|
WavemobileSim
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
name = 'Wavemobile-SIM'
|
|
|
|
|
|
|
|
|
|
def __init__(self, ssc):
|
|
|
|
|
super(WavemobileSim, self).__init__(ssc)
|
|
|
|
|
self._adm_chv_num = 0x0A
|
|
|
|
|
self._scc.cla_byte = "00"
|
|
|
|
|
self._scc.sel_ctrl = "0004" #request an FCP
|
|
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
|
def autodetect(kls, scc):
|
|
|
|
|
try:
|
|
|
|
|
# Look for ATR
|
|
|
|
|
if scc.get_atr() == toBytes("3B 9F 95 80 1F C7 80 31 E0 73 F6 21 13 67 4D 45 16 00 43 01 00 8F"):
|
|
|
|
|
return kls(scc)
|
|
|
|
|
except:
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
if not p['pin_adm']:
|
|
|
|
|
raise ValueError("Please provide a PIN-ADM as there is no default one")
|
2021-03-11 12:59:44 +00:00
|
|
|
|
self.verify_adm(h2b(p['pin_adm']))
|
2018-07-04 15:57:20 +00:00
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.ICCID
|
|
|
|
|
# TODO: Add programming of the ICCID
|
|
|
|
|
if p.get('iccid'):
|
2018-07-04 15:57:20 +00:00
|
|
|
|
print("Warning: Programming of the ICCID is not implemented for this type of card.")
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# KI (Presumably a propritary file)
|
|
|
|
|
# TODO: Add programming of KI
|
|
|
|
|
if p.get('ki'):
|
2018-07-04 15:57:20 +00:00
|
|
|
|
print("Warning: Programming of the KI is not implemented for this type of card.")
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# OPc (Presumably a propritary file)
|
|
|
|
|
# TODO: Add programming of OPc
|
|
|
|
|
if p.get('opc'):
|
2018-07-04 15:57:20 +00:00
|
|
|
|
print("Warning: Programming of the OPc is not implemented for this type of card.")
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.SMSP
|
2018-07-04 15:57:20 +00:00
|
|
|
|
if p.get('smsp'):
|
|
|
|
|
sw = self.update_smsp(p['smsp'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming SMSP failed with code %s"%sw)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.IMSI
|
2018-07-04 15:57:20 +00:00
|
|
|
|
if p.get('imsi'):
|
|
|
|
|
sw = self.update_imsi(p['imsi'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming IMSI failed with code %s"%sw)
|
|
|
|
|
|
|
|
|
|
# EF.ACC
|
|
|
|
|
if p.get('acc'):
|
|
|
|
|
sw = self.update_acc(p['acc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming ACC failed with code %s"%sw)
|
|
|
|
|
|
|
|
|
|
# EF.PLMNsel
|
2019-09-11 23:46:25 +00:00
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
|
|
|
|
sw = self.update_plmnsel(p['mcc'], p['mnc'])
|
|
|
|
|
if sw != '9000':
|
2018-07-04 15:57:20 +00:00
|
|
|
|
print("Programming PLMNsel failed with code %s"%sw)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.PLMNwAcT
|
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
2018-07-04 15:57:20 +00:00
|
|
|
|
sw = self.update_plmn_act(p['mcc'], p['mnc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming PLMNwAcT failed with code %s"%sw)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.OPLMNwAcT
|
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
2018-07-04 15:57:20 +00:00
|
|
|
|
sw = self.update_oplmn_act(p['mcc'], p['mnc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming OPLMNwAcT failed with code %s"%sw)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
# EF.AD
|
2021-02-24 13:06:18 +00:00
|
|
|
|
if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
|
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
|
|
|
|
mnc = p['mnc']
|
|
|
|
|
else:
|
|
|
|
|
mnc = None
|
|
|
|
|
sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
|
2019-04-01 14:33:48 +00:00
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming AD failed with code %s"%sw)
|
|
|
|
|
|
2019-09-11 23:46:25 +00:00
|
|
|
|
return None
|
2018-07-04 15:57:20 +00:00
|
|
|
|
|
2018-04-25 20:36:29 +00:00
|
|
|
|
|
2020-12-23 08:25:46 +00:00
|
|
|
|
class SysmoISIMSJA2(UsimCard, IsimCard):
|
2019-12-31 16:55:47 +00:00
|
|
|
|
"""
|
|
|
|
|
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)
|
2020-03-11 11:32:44 +00:00
|
|
|
|
|
|
|
|
|
# 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)
|
2019-12-31 16:55:47 +00:00
|
|
|
|
except:
|
|
|
|
|
return None
|
|
|
|
|
return None
|
|
|
|
|
|
2021-01-08 19:19:11 +00:00
|
|
|
|
def verify_adm(self, key):
|
2019-12-31 16:55:47 +00:00
|
|
|
|
# authenticate as ADM using default key (written on the card..)
|
2021-01-08 19:19:11 +00:00
|
|
|
|
if not key:
|
2019-12-31 16:55:47 +00:00
|
|
|
|
raise ValueError("Please provide a PIN-ADM as there is no default one")
|
2021-01-08 19:19:11 +00:00
|
|
|
|
(res, sw) = self._scc.verify_chv(0x0A, key)
|
|
|
|
|
return sw
|
|
|
|
|
|
|
|
|
|
def program(self, p):
|
|
|
|
|
self.verify_adm(h2b(p['pin_adm']))
|
2019-12-31 16:55:47 +00:00
|
|
|
|
|
|
|
|
|
# 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
|
2021-01-21 15:06:50 +00:00
|
|
|
|
self._scc.select_path(['7f20'])
|
2019-12-31 16:55:47 +00:00
|
|
|
|
|
2021-04-06 10:04:34 +00:00
|
|
|
|
# set Service Provider Name
|
|
|
|
|
if p.get('name') is not None:
|
2021-05-07 13:23:20 +00:00
|
|
|
|
self.update_spn(p['name'], True, True)
|
2021-04-06 10:04:34 +00:00
|
|
|
|
|
2019-12-31 16:55:47 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
2020-05-05 15:35:57 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
2019-12-31 16:55:47 +00:00
|
|
|
|
# EF.AD
|
2021-02-24 13:06:18 +00:00
|
|
|
|
if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
|
|
|
|
|
if p.get('mcc') and p.get('mnc'):
|
|
|
|
|
mnc = p['mnc']
|
|
|
|
|
else:
|
|
|
|
|
mnc = None
|
|
|
|
|
sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
|
2019-12-31 16:55:47 +00:00
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming AD failed with code %s"%sw)
|
|
|
|
|
|
|
|
|
|
# EF.SMSP
|
|
|
|
|
if p.get('smsp'):
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f10'])
|
2019-12-31 16:55:47 +00:00
|
|
|
|
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
|
|
|
|
|
|
2020-03-26 09:00:45 +00:00
|
|
|
|
# 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'])
|
2021-04-20 20:38:21 +00:00
|
|
|
|
content = 'ff' * 20 + msisdn
|
2020-03-26 09:00:45 +00:00
|
|
|
|
|
2021-01-21 15:06:50 +00:00
|
|
|
|
r = self._scc.select_path(['3f00', '7f10'])
|
2020-03-26 09:00:45 +00:00
|
|
|
|
data, sw = self._scc.update_record('6F40', 1, content, force_len=True)
|
|
|
|
|
|
2020-03-26 09:03:25 +00:00
|
|
|
|
# EF.ACC
|
|
|
|
|
if p.get('acc'):
|
|
|
|
|
sw = self.update_acc(p['acc'])
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming ACC failed with code %s"%sw)
|
|
|
|
|
|
2020-03-23 11:06:29 +00:00
|
|
|
|
# Populate AIDs
|
|
|
|
|
self.read_aids()
|
|
|
|
|
|
2019-12-31 16:55:47 +00:00
|
|
|
|
# update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
|
|
|
|
|
# hard linked to EF-USIM_AUTH_KEY)
|
2021-01-21 15:06:50 +00:00
|
|
|
|
self._scc.select_path(['3f00'])
|
|
|
|
|
self._scc.select_path(['a515'])
|
2019-12-31 16:55:47 +00:00
|
|
|
|
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
|
2021-03-11 12:03:18 +00:00
|
|
|
|
data, sw = self.select_adf_by_aid(adf="isim")
|
|
|
|
|
if sw == '9000':
|
2020-03-11 11:18:29 +00:00
|
|
|
|
if p.get('ki'):
|
|
|
|
|
self._scc.update_binary('af20', p['ki'], 1)
|
|
|
|
|
if p.get('opc'):
|
|
|
|
|
self._scc.update_binary('af20', p['opc'], 17)
|
2019-12-31 16:55:47 +00:00
|
|
|
|
|
2020-03-24 16:32:21 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
|
|
|
|
|
2020-03-25 10:43:19 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
2020-03-26 08:16:14 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
2020-03-26 08:27:45 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
2021-03-11 12:03:18 +00:00
|
|
|
|
data, sw = self.select_adf_by_aid(adf="usim")
|
|
|
|
|
if sw == '9000':
|
2020-06-03 13:19:40 +00:00
|
|
|
|
# update EF-USIM_AUTH_KEY in ADF.USIM
|
2020-03-11 11:18:29 +00:00
|
|
|
|
if p.get('ki'):
|
|
|
|
|
self._scc.update_binary('af20', p['ki'], 1)
|
|
|
|
|
if p.get('opc'):
|
|
|
|
|
self._scc.update_binary('af20', p['opc'], 17)
|
2019-12-31 16:55:47 +00:00
|
|
|
|
|
2020-06-03 13:19:40 +00:00
|
|
|
|
# update EF.EHPLMN in ADF.USIM
|
2020-08-31 13:04:19 +00:00
|
|
|
|
if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
|
2020-06-03 13:19:40 +00:00
|
|
|
|
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)
|
2020-03-23 11:10:56 +00:00
|
|
|
|
|
|
|
|
|
# update EF.ePDGId in ADF.USIM
|
|
|
|
|
if self.file_exists(EF_USIM_ADF_map['ePDGId']):
|
|
|
|
|
if p.get('epdgid'):
|
2020-09-29 07:44:24 +00:00
|
|
|
|
sw = self.update_epdgid(p['epdgid'])
|
2020-03-25 11:51:38 +00:00
|
|
|
|
else:
|
|
|
|
|
sw = self.update_epdgid("")
|
|
|
|
|
if sw != '9000':
|
|
|
|
|
print("Programming ePDGId failed with code %s"%sw)
|
2020-03-23 11:10:56 +00:00
|
|
|
|
|
2020-03-24 12:15:37 +00:00
|
|
|
|
# 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)
|
|
|
|
|
|
|
|
|
|
|
2020-03-24 12:26:53 +00:00
|
|
|
|
# After successfully programming EF.ePDGId and EF.ePDGSelection,
|
|
|
|
|
# Set service 106 and 107 as available in EF.UST
|
2020-03-25 09:34:28 +00:00
|
|
|
|
# Disable service 95, 99, 115 if ISIM application is present
|
2020-03-24 12:26:53 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2020-03-25 09:34:28 +00:00
|
|
|
|
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)
|
|
|
|
|
|
2019-12-31 16:55:47 +00:00
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
2018-04-25 20:36:29 +00:00
|
|
|
|
# In order for autodetection ...
|
2011-12-07 11:34:14 +00:00
|
|
|
|
_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
|
2018-01-10 05:18:32 +00:00
|
|
|
|
SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
|
2019-12-31 16:55:47 +00:00
|
|
|
|
FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2 ]
|
2018-01-10 05:17:55 +00:00
|
|
|
|
|
2020-03-18 10:38:00 +00:00
|
|
|
|
def card_detect(ctype, scc):
|
|
|
|
|
# Detect type if needed
|
|
|
|
|
card = None
|
|
|
|
|
ctypes = dict([(kls.name, kls) for kls in _cards_classes])
|
|
|
|
|
|
2021-10-05 12:42:01 +00:00
|
|
|
|
if ctype == "auto":
|
2020-03-18 10:38:00 +00:00
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
elif ctype in ctypes:
|
|
|
|
|
card = ctypes[ctype](scc)
|
|
|
|
|
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError("Unknown card type: %s" % ctype)
|
|
|
|
|
|
|
|
|
|
return card
|