pysim/pySim/cards.py

1679 lines
54 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
""" pySim: Card programmation logic
"""
#
# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
# Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
# Copyright (C) 2017 Alexander.Chemeris <Alexander.Chemeris@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 typing import Optional, Dict, Tuple
import abc
from pySim.ts_51_011 import EF, DF, EF_AD, EF_SPN
from pySim.ts_31_102 import EF_USIM_ADF_map
from pySim.ts_31_103 import EF_ISIM_ADF_map
from pySim.utils import *
from smartcard.util import toBytes
from pytlv.TLV import *
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
class SimCard:
name = 'SIM'
def __init__(self, scc):
self._scc = scc
self._adm_chv_num = 4
self._aids = []
def reset(self):
rc = self._scc.reset_card()
if rc == 1:
return self._scc.get_atr()
else:
return None
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_path(fid)
for res in res_arr:
if res[1] != '9000':
return False
return True
def verify_adm(self, key):
"""Authenticate with ADM key"""
(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):
data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4, c='0'))
return sw
def read_hplmn_act(self):
(res, sw) = self._scc.read_binary(EF['HPLMNAcT'])
if sw == '9000':
return (format_xplmn_w_act(res), sw)
else:
return (None, sw)
def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
"""
Update Home PLMN with access technology bit-field
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
access_tech = 'FFFF' # All technologies selected, even Reserved for Future Use ones
"""
# get size and write EF.HPLMNwAcT
data = self._scc.read_binary(EF['HPLMNwAcT'], length=None, offset=0)
size = len(data[0]) // 2
hplmn = enc_plmn(mcc, mnc)
content = hplmn + access_tech
data, sw = self._scc.update_binary(
EF['HPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
return sw
def read_oplmn_act(self):
(res, sw) = self._scc.read_binary(EF['OPLMNwAcT'])
if sw == '9000':
return (format_xplmn_w_act(res), sw)
else:
return (None, sw)
def update_oplmn_act(self, mcc, mnc, access_tech='FFFF'):
"""get size and write EF.OPLMNwAcT, See note in update_hplmn_act()"""
data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
size = len(data[0]) // 2
hplmn = enc_plmn(mcc, mnc)
content = hplmn + access_tech
data, sw = self._scc.update_binary(
EF['OPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
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'):
"""get size and write EF.PLMNwAcT, See note in update_hplmn_act()"""
data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
size = len(data[0]) // 2
hplmn = enc_plmn(mcc, mnc)
content = hplmn + access_tech
data, sw = self._scc.update_binary(
EF['PLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
return sw
def update_plmnsel(self, mcc, mnc):
data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
size = len(data[0]) // 2
hplmn = enc_plmn(mcc, mnc)
data, sw = self._scc.update_binary(
EF['PLMNsel'], hplmn + 'ff' * (size-3))
return sw
def update_smsp(self, smsp):
data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 84))
return sw
def update_ad(self, mnc=None, opmode=None, ofm=None, path=EF['AD']):
"""
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.
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
path (optional list with file path e.g. ['3f00', '7f20', '6fad'])
Returns:
str: Return code of write operation
"""
ad = EF_AD()
# read from card
raw_hex_data, sw = self._scc.read_binary(
path, length=None, offset=0)
abstract_data = ad.decode_hex(raw_hex_data)
# perform updates
if mnc and abstract_data['extensions']:
# Note: Since we derive the length of the MNC by the string length
# of the mnc parameter, the caller must ensure that mnc has the
# correct length and is padded with zeros (if necessary).
mnclen = len(str(mnc))
if mnclen > 3 or mnclen < 2:
raise RuntimeError('invalid length of mnc "{}", expecting 2 or 3 digits'.format(mnc))
abstract_data['extensions']['mnc_len'] = mnclen
if opmode:
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
else:
raise RuntimeError('invalid opmode "{}"'.format(opmode))
if ofm:
abstract_data['ofm'] = bool(int(ofm, 16))
# write to card
raw_hex_data = ad.encode_hex(abstract_data)
data, sw = self._scc.update_binary(path, raw_hex_data)
return sw
def read_spn(self):
(content, sw) = self._scc.read_binary(EF['SPN'])
if sw == '9000':
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)
else:
return (None, sw)
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)
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)
def read_aids(self):
"""Fetch all the AIDs present on UICC"""
self._aids = []
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),))
self._aids = []
return self._aids
@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"
adf = adf.lower()
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
def select_adf_by_aid(self, adf="usim"):
"""Select ADF.U/ISIM in the Card using its full AID"""
if is_hex(adf):
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)
else:
# If we cannot get the full AID, try with short AID
return self._scc.select_adf(aid)
return (None, None)
def erase_binary(self, ef):
"""Erase the contents of a file"""
len = self._scc.binary_size(ef)
self._scc.update_binary(ef, "ff" * len, offset=0, verify=True)
def erase_record(self, ef, rec_no):
"""Erase the contents of a single record"""
len = self._scc.record_size(ef)
self._scc.update_record(ef, rec_no, "ff" * len,
force_len=False, verify=True)
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)
class UsimCard(SimCard):
name = 'USIM'
def __init__(self, ssc):
super(UsimCard, self).__init__(ssc)
# See also: ETSI TS 102 221, Table 9.3
self._adm_chv_num = 0xA0
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':
try:
addr, addr_type = dec_addr_tlv(res)
except:
addr = None
addr_type = None
return (format_addr(addr, addr_type), 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
def update_est(self, service, bit=1):
(res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EST'])
if sw == '9000':
content = enc_st(res, service, bit)
(res, sw) = self._scc.update_binary(
EF_USIM_ADF_map['EST'], content)
return sw
class IsimCard(SimCard):
name = 'ISIM'
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':
try:
addr, addr_type = dec_addr_tlv(res)
except:
addr = None
addr_type = None
content = format_addr(addr, addr_type)
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 initial 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 initial 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 initial 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 initial 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
def update_ist(self, service, bit=1):
(res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IST'])
if sw == '9000':
content = enc_st(res, service, bit)
(res, sw) = self._scc.update_binary(
EF_ISIM_ADF_map['IST'], content)
return sw
class MagicSimBase(abc.ABC, SimCard):
"""
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
- [1 .. N] for the programmable EFs
* 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
"""
_files = {} # type: Dict[str, Tuple[str, int, bool]]
_ki_file = None # type: Optional[str]
@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']
r = self._scc.select_path(['3f00', '7f4d', f[0]])
rec_len = int(r[-1][28:30], 16)
tlen = int(r[-1][4:8], 16)
rec_cnt = (tlen // rec_len) - 1
if (rec_cnt < 1) or (rec_len != f[1]):
raise RuntimeError('Bad card type')
return rec_cnt
def program(self, p):
# Go to dir
self._scc.select_path(['3f00', '7f4d'])
# Home PLMN in PLMN_Sel format
hplmn = enc_plmn(p['mcc'], p['mnc'])
# 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
v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
# IMSI
v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
# Ki
if self._ki_file:
v += self._ki_file + '10' + p['ki']
# PLMN_Sel
v += '6f30' + '18' + rpad(hplmn, 36)
# 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)
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
r = self._scc.select_path(['3f00', '7f20', '6f30'])
tl = int(r[-1][4:8], 16)
hplmn = enc_plmn(p['mcc'], p['mnc'])
self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
def erase(self):
# Dummy
df = {}
for k, v in self._files.items():
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()):
for k, (msg, ofs) in df.items():
self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
class SuperSim(MagicSimBase):
name = 'supersim'
_files = {
'name': ('8f0c', 18, True),
'b_ef': ('8f0d', 74, True),
'r_ef': ('8f0e', 50, True),
}
_ki_file = None
class MagicSim(MagicSimBase):
name = 'magicsim'
_files = {
'name': ('8f0c', 18, True),
'b_ef': ('8f0d', 130, True),
'r_ef': ('8f0e', 102, False),
}
_ki_file = '6f1b'
class FakeMagicSim(SimCard):
"""
Theses cards have a record based EF 3f00/000c that contains the provider
information. See the program method for its format. The records go from
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
"""
r = self._scc.select_path(['3f00', '000c'])
rec_len = int(r[-1][28:30], 16)
tlen = int(r[-1][4:8], 16)
rec_cnt = (tlen // rec_len) - 1
if (rec_cnt < 1) or (rec_len != 0x5a):
raise RuntimeError('Bad card type')
return rec_cnt, rec_len
def program(self, p):
# Home PLMN
r = self._scc.select_path(['3f00', '7f20', '6f30'])
tl = int(r[-1][4:8], 16)
hplmn = enc_plmn(p['mcc'], p['mnc'])
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 = (
'81' + # 1b Status: Valid & Active
rpad(s2h(p['name'][0:14]), 28) + # 14b Entry Name
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)
)
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)
class GrcardSim(SimCard):
"""
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
if p['pin_adm']:
pin = h2b(p['pin_adm'])
else:
pin = h2b("4444444444444444")
self._scc.verify_chv(5, pin)
# EF.ICCID
r = self._scc.select_path(['3f00', '2fe2'])
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
# EF.IMSI
r = self._scc.select_path(['3f00', '7f20', '6f07'])
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
# EF.ACC
if p.get('acc') is not None:
data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
# EF.SMSP
if p.get('smsp'):
r = self._scc.select_path(['3f00', '7f10', '6f42'])
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
# Set the Ki using proprietary command
pdu = '80d4020010' + p['ki']
data, sw = self._scc._tp.send_apdu(pdu)
# EF.HPLMN
r = self._scc.select_path(['3f00', '7f20', '6f30'])
size = int(r[-1][4:8], 16)
hplmn = enc_plmn(p['mcc'], p['mnc'])
self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
# EF.SPN (Service Provider Name)
r = self._scc.select_path(['3f00', '7f20', '6f30'])
size = int(r[-1][4:8], 16)
# FIXME
# FIXME: EF.MSISDN
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'
@classmethod
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
class SysmoUSIMgr1(UsimCard):
"""
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
p['opc'] + # 32b OPC
enc_iccid(p['iccid']) + # 10b ICCID
enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
)
data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
class SysmoSIMgr2(SimCard):
"""
sysmocom sysmoSIM-GR2
"""
name = 'sysmoSIM-GR2'
@classmethod
def autodetect(kls, scc):
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
return None
def program(self, p):
# select MF
r = self._scc.select_path(['3f00'])
# 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)
if p['pin_adm']:
pin = h2b(p['pin_adm'])
else:
pin = h2b("4444444444444444")
pdu = 'A0D43A0508' + b2h(pin)
data, sw = self._scc._tp.send_apdu(pdu)
# authenticate as ADM (enough to write file, and can set PINs)
self._scc.verify_chv(0x05, pin)
# write EF.ICCID
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
# select DF_GSM
r = self._scc.select_path(['7f20'])
# 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
r = self._scc.select_path(['6f30'])
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
r = self._scc.select_path(['3f00', '7f10'])
# write EF.SMSP
if p.get('smsp'):
data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
class SysmoUSIMSJS1(UsimCard):
"""
sysmocom sysmoUSIM-SJS1
"""
name = 'sysmoUSIM-SJS1'
def __init__(self, ssc):
super(SysmoUSIMSJS1, self).__init__(ssc)
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 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
return None
def verify_adm(self, key):
# authenticate as ADM using default key (written on the card..)
if not key:
raise ValueError(
"Please provide a PIN-ADM as there is no default one")
(res, sw) = self._scc.verify_chv(0x0A, key)
return sw
def program(self, p):
self.verify_adm(h2b(p['pin_adm']))
# select MF
r = self._scc.select_path(['3f00'])
# write EF.ICCID
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
# select DF_GSM
r = self._scc.select_path(['7f20'])
# set Ki in proprietary file
data, sw = self._scc.update_binary('00FF', p['ki'])
# set OPc in proprietary file
if 'opc' in p:
content = "01" + p['opc']
data, sw = self._scc.update_binary('00F7', content)
# set Service Provider Name
if p.get('name') is not None:
self.update_spn(p['name'], True, True)
if p.get('acc') is not None:
self.update_acc(p['acc'])
# write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
# EF.PLMNsel
if p.get('mcc') and p.get('mnc'):
sw = self.update_plmnsel(p['mcc'], p['mnc'])
if sw != '9000':
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')) 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'))
if sw != '9000':
print("Programming AD failed with code %s" % sw)
# EF.SMSP
if p.get('smsp'):
r = self._scc.select_path(['3f00', '7f10'])
data, sw = self._scc.update_record(
'6f42', 1, lpad(p['smsp'], 104), force_len=True)
# EF.MSISDN
# TODO: Alpha Identifier (currently 'ff'O * 20)
# TODO: Capability/Configuration1 Record Identifier
# TODO: Extension1 Record Identifier
if p.get('msisdn') is not None:
msisdn = enc_msisdn(p['msisdn'])
data = 'ff' * 20 + msisdn
r = self._scc.select_path(['3f00', '7f10'])
data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
class FairwavesSIM(UsimCard):
"""
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
"""
name = 'Fairwaves-SIM'
# 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):
# 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):
# authenticate as ADM1
if not p['pin_adm']:
raise ValueError(
"Please provide a PIN-ADM as there is no default one")
self.verify_adm(h2b(p['pin_adm']))
# 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)
class OpenCellsSim(SimCard):
"""
OpenCellsSim
"""
name = 'OpenCells-SIM'
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
r = self._scc.select_path(['3f00'])
# write EF.ICCID
data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
r = self._scc.select_path(['7ff0'])
# 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
r = self._scc.select_path(['7f20'])
# write EF.IMSI
data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
class WavemobileSim(UsimCard):
"""
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")
self.verify_adm(h2b(p['pin_adm']))
# EF.ICCID
# TODO: Add programming of the ICCID
if p.get('iccid'):
print(
"Warning: Programming of the ICCID is not implemented for this type of card.")
# KI (Presumably a proprietary file)
# TODO: Add programming of KI
if p.get('ki'):
print(
"Warning: Programming of the KI is not implemented for this type of card.")
# OPc (Presumably a proprietary file)
# TODO: Add programming of OPc
if p.get('opc'):
print(
"Warning: Programming of the OPc is not implemented for this type of card.")
# EF.SMSP
if p.get('smsp'):
sw = self.update_smsp(p['smsp'])
if sw != '9000':
print("Programming SMSP failed with code %s" % sw)
# EF.IMSI
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
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.AD
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'))
if sw != '9000':
print("Programming AD failed with code %s" % sw)
return None
class SysmoISIMSJA2(UsimCard, IsimCard):
"""
sysmocom sysmoISIM-SJA2
"""
name = 'sysmoISIM-SJA2'
def __init__(self, ssc):
super(SysmoISIMSJA2, self).__init__(ssc)
self._scc.cla_byte = "00"
self._scc.sel_ctrl = "0004" # request an FCP
@classmethod
def autodetect(kls, scc):
try:
# Try card model #1
atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9"
if scc.get_atr() == toBytes(atr):
return kls(scc)
# Try card model #2
atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2"
if scc.get_atr() == toBytes(atr):
return kls(scc)
# Try card model #3
atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"
if scc.get_atr() == toBytes(atr):
return kls(scc)
except:
return None
return None
def verify_adm(self, key):
# authenticate as ADM using default key (written on the card..)
if not key:
raise ValueError(
"Please provide a PIN-ADM as there is no default one")
(res, sw) = self._scc.verify_chv(0x0A, key)
return sw
def program(self, p):
self.verify_adm(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_path(['7f20'])
# set Service Provider Name
if p.get('name') is not None:
self.update_spn(p['name'], True, True)
# 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')) 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'))
if sw != '9000':
print("Programming AD failed with code %s" % sw)
# EF.SMSP
if p.get('smsp'):
r = self._scc.select_path(['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
r = self._scc.select_path(['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_path(['3f00'])
self._scc.select_path(['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
data, sw = self.select_adf_by_aid(adf="isim")
if sw == '9000':
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)
data, sw = self.select_adf_by_aid(adf="usim")
if sw == '9000':
# EF.AD in ADF.USIM
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'),
path=EF_USIM_ADF_map['AD'])
if sw != '9000':
print("Programming AD failed with code %s" % sw)
# update EF-USIM_AUTH_KEY in ADF.USIM
if p.get('ki'):
self._scc.update_binary('af20', p['ki'], 1)
if p.get('opc'):
self._scc.update_binary('af20', p['opc'], 17)
# update EF.EHPLMN in ADF.USIM
if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
if p.get('mcc') and p.get('mnc'):
sw = self.update_ehplmn(p['mcc'], p['mnc'])
if sw != '9000':
print("Programming EHPLMN failed with code %s" % sw)
# update EF.ePDGId in ADF.USIM
if self.file_exists(EF_USIM_ADF_map['ePDGId']):
if p.get('epdgid'):
sw = self.update_epdgid(p['epdgid'])
else:
sw = self.update_epdgid("")
if sw != '9000':
print("Programming ePDGId failed with code %s" % sw)
# update EF.ePDGSelection in ADF.USIM
if self.file_exists(EF_USIM_ADF_map['ePDGSelection']):
if p.get('epdgSelection'):
epdg_plmn = p['epdgSelection']
sw = self.update_ePDGSelection(
epdg_plmn[:3], epdg_plmn[3:])
else:
sw = self.update_ePDGSelection("", "")
if sw != '9000':
print("Programming ePDGSelection failed with code %s" % sw)
# After successfully programming EF.ePDGId and EF.ePDGSelection,
# Set service 106 and 107 as available in EF.UST
# Disable service 95, 99, 115 if ISIM application is present
if self.file_exists(EF_USIM_ADF_map['UST']):
if p.get('epdgSelection') and p.get('epdgid'):
sw = self.update_ust(106, 1)
if sw != '9000':
print("Programming UST failed with code %s" % sw)
sw = self.update_ust(107, 1)
if sw != '9000':
print("Programming UST failed with code %s" % sw)
sw = self.update_ust(95, 0)
if sw != '9000':
print("Programming UST failed with code %s" % sw)
sw = self.update_ust(99, 0)
if sw != '9000':
print("Programming UST failed with code %s" % sw)
sw = self.update_ust(115, 0)
if sw != '9000':
print("Programming UST failed with code %s" % sw)
return
# In order for autodetection ...
_cards_classes = [FakeMagicSim, SuperSim, MagicSim, GrcardSim,
SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2]
def card_detect(ctype, scc):
# Detect type if needed
card = None
ctypes = dict([(kls.name, kls) for kls in _cards_classes])
if ctype == "auto":
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