blob: 0f34f9b50a154453e776581b9ff16f39feea6b4b [file] [log] [blame]
Sylvain Munaut76504e02010-12-07 00:24:32 +01001# -*- coding: utf-8 -*-
2
3""" pySim: Card programmation logic
4"""
5
6#
7# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
Harald Welte3156d902011-03-22 21:48:19 +01008# Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
Alexander Chemeriseb6807d2017-07-18 17:04:38 +03009# Copyright (C) 2017 Alexander.Chemeris <Alexander.Chemeris@gmail.com>
Sylvain Munaut76504e02010-12-07 00:24:32 +010010#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation, either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program. If not, see <http://www.gnu.org/licenses/>.
23#
24
Vadim Yanitskiy03c67f72021-05-02 02:10:39 +020025from typing import Optional, Dict, Tuple
Vadim Yanitskiy85302d62021-05-02 02:18:42 +020026import abc
Vadim Yanitskiy03c67f72021-05-02 02:10:39 +020027
Robert Falkenbergb07a3e92021-05-07 15:23:20 +020028from pySim.ts_51_011 import EF, DF, EF_AD, EF_SPN
Harald Welteca673942020-06-03 15:19:40 +020029from pySim.ts_31_102 import EF_USIM_ADF_map
Supreeth Herle5ad9aec2020-03-24 17:26:40 +010030from pySim.ts_31_103 import EF_ISIM_ADF_map
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030031from pySim.utils import *
Alexander Chemeris8ad124a2018-01-10 14:17:55 +090032from smartcard.util import toBytes
Supreeth Herle79f43dd2020-03-25 11:43:19 +010033from pytlv.TLV import *
Sylvain Munaut76504e02010-12-07 00:24:32 +010034
Harald Weltec91085e2022-02-10 18:05:45 +010035
36def format_addr(addr: str, addr_type: str) -> str:
37 """
38 helper function to format an FQDN (addr_type = '00') or IPv4
39 (addr_type = '01') address string into a printable string that
40 contains the hexadecimal representation and the original address
41 string (addr)
42 """
43 res = ""
44 if addr_type == '00': # FQDN
45 res += "\t%s # %s\n" % (s2h(addr), addr)
46 elif addr_type == '01': # IPv4
47 octets = addr.split(".")
48 addr_hex = ""
49 for o in octets:
50 addr_hex += ("%02x" % int(o))
51 res += "\t%s # %s\n" % (addr_hex, addr)
52 return res
53
Philipp Maierbe18f2a2021-04-30 15:00:27 +020054
Vadim Yanitskiy04b5d9d2022-07-07 03:05:30 +070055class SimCard:
Sylvain Munaut76504e02010-12-07 00:24:32 +010056
Harald Weltec91085e2022-02-10 18:05:45 +010057 name = 'SIM'
Philipp Maierfc5f28d2021-05-05 12:18:41 +020058
Harald Weltec91085e2022-02-10 18:05:45 +010059 def __init__(self, scc):
60 self._scc = scc
61 self._adm_chv_num = 4
62 self._aids = []
Sylvain Munaut76504e02010-12-07 00:24:32 +010063
Harald Weltec91085e2022-02-10 18:05:45 +010064 def reset(self):
65 rc = self._scc.reset_card()
Vadim Yanitskiyb9544512022-04-21 16:46:03 +030066 if rc == 1:
Harald Weltec91085e2022-02-10 18:05:45 +010067 return self._scc.get_atr()
68 else:
69 return None
Sylvain Munaut76504e02010-12-07 00:24:32 +010070
Harald Weltec91085e2022-02-10 18:05:45 +010071 def erase(self):
72 print("warning: erasing is not supported for specified card type!")
73 return
Philipp Maierd58c6322020-05-12 16:47:45 +020074
Harald Weltec91085e2022-02-10 18:05:45 +010075 def file_exists(self, fid):
76 res_arr = self._scc.try_select_path(fid)
77 for res in res_arr:
78 if res[1] != '9000':
79 return False
80 return True
Harald Welteca673942020-06-03 15:19:40 +020081
Harald Weltec91085e2022-02-10 18:05:45 +010082 def verify_adm(self, key):
83 """Authenticate with ADM key"""
84 (res, sw) = self._scc.verify_chv(self._adm_chv_num, key)
85 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030086
Harald Weltec91085e2022-02-10 18:05:45 +010087 def read_iccid(self):
88 (res, sw) = self._scc.read_binary(EF['ICCID'])
89 if sw == '9000':
90 return (dec_iccid(res), sw)
91 else:
92 return (None, sw)
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030093
Matan Perelmanc296cb52023-05-11 12:49:17 +030094 def update_iccid(self, iccid):
95 data, sw = self._scc.update_binary(EF['ICCID'], enc_iccid(iccid))
96 return sw
97
Harald Weltec91085e2022-02-10 18:05:45 +010098 def read_imsi(self):
99 (res, sw) = self._scc.read_binary(EF['IMSI'])
100 if sw == '9000':
101 return (dec_imsi(res), sw)
102 else:
103 return (None, sw)
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300104
Harald Weltec91085e2022-02-10 18:05:45 +0100105 def update_imsi(self, imsi):
106 data, sw = self._scc.update_binary(EF['IMSI'], enc_imsi(imsi))
107 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300108
Harald Weltec91085e2022-02-10 18:05:45 +0100109 def update_acc(self, acc):
110 data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4, c='0'))
111 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300112
Harald Weltec91085e2022-02-10 18:05:45 +0100113 def read_hplmn_act(self):
114 (res, sw) = self._scc.read_binary(EF['HPLMNAcT'])
115 if sw == '9000':
116 return (format_xplmn_w_act(res), sw)
117 else:
118 return (None, sw)
Supreeth Herlea850a472020-03-19 12:44:11 +0100119
Harald Weltec91085e2022-02-10 18:05:45 +0100120 def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
121 """
122 Update Home PLMN with access technology bit-field
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300123
Harald Weltec91085e2022-02-10 18:05:45 +0100124 See Section "10.3.37 EFHPLMNwAcT (HPLMN Selector with Access Technology)"
125 in ETSI TS 151 011 for the details of the access_tech field coding.
126 Some common values:
127 access_tech = '0080' # Only GSM is selected
128 access_tech = 'FFFF' # All technologies selected, even Reserved for Future Use ones
129 """
130 # get size and write EF.HPLMNwAcT
131 data = self._scc.read_binary(EF['HPLMNwAcT'], length=None, offset=0)
132 size = len(data[0]) // 2
133 hplmn = enc_plmn(mcc, mnc)
134 content = hplmn + access_tech
135 data, sw = self._scc.update_binary(
136 EF['HPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
137 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300138
Harald Weltec91085e2022-02-10 18:05:45 +0100139 def read_oplmn_act(self):
140 (res, sw) = self._scc.read_binary(EF['OPLMNwAcT'])
141 if sw == '9000':
142 return (format_xplmn_w_act(res), sw)
143 else:
144 return (None, sw)
Supreeth Herle1757b262020-03-19 12:43:11 +0100145
Harald Weltec91085e2022-02-10 18:05:45 +0100146 def update_oplmn_act(self, mcc, mnc, access_tech='FFFF'):
147 """get size and write EF.OPLMNwAcT, See note in update_hplmn_act()"""
148 data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
149 size = len(data[0]) // 2
150 hplmn = enc_plmn(mcc, mnc)
151 content = hplmn + access_tech
152 data, sw = self._scc.update_binary(
153 EF['OPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
154 return sw
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200155
Harald Weltec91085e2022-02-10 18:05:45 +0100156 def read_plmn_act(self):
157 (res, sw) = self._scc.read_binary(EF['PLMNwAcT'])
158 if sw == '9000':
159 return (format_xplmn_w_act(res), sw)
160 else:
161 return (None, sw)
Supreeth Herle14084402020-03-19 12:42:10 +0100162
Harald Weltec91085e2022-02-10 18:05:45 +0100163 def update_plmn_act(self, mcc, mnc, access_tech='FFFF'):
164 """get size and write EF.PLMNwAcT, See note in update_hplmn_act()"""
165 data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
166 size = len(data[0]) // 2
167 hplmn = enc_plmn(mcc, mnc)
168 content = hplmn + access_tech
169 data, sw = self._scc.update_binary(
170 EF['PLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
171 return sw
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200172
Harald Weltec91085e2022-02-10 18:05:45 +0100173 def update_plmnsel(self, mcc, mnc):
174 data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
175 size = len(data[0]) // 2
176 hplmn = enc_plmn(mcc, mnc)
177 data, sw = self._scc.update_binary(
178 EF['PLMNsel'], hplmn + 'ff' * (size-3))
179 return sw
Philipp Maier5bf42602018-07-11 23:23:40 +0200180
Harald Weltec91085e2022-02-10 18:05:45 +0100181 def update_smsp(self, smsp):
182 data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 84))
183 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300184
Philipp Maier284ac102023-01-17 14:26:56 +0100185 def update_ad(self, mnc=None, opmode=None, ofm=None, path=EF['AD']):
Harald Weltec91085e2022-02-10 18:05:45 +0100186 """
187 Update Administrative Data (AD)
Philipp Maieree908ae2019-03-21 16:21:12 +0100188
Harald Weltec91085e2022-02-10 18:05:45 +0100189 See Sec. "4.2.18 EF_AD (Administrative Data)"
190 in 3GPP TS 31.102 for the details of the EF_AD contents.
Philipp Maier7f9f64a2020-05-11 21:28:52 +0200191
Harald Weltec91085e2022-02-10 18:05:45 +0100192 Set any parameter to None to keep old value(s) on card.
Philipp Maier7f9f64a2020-05-11 21:28:52 +0200193
Harald Weltec91085e2022-02-10 18:05:45 +0100194 Parameters:
195 mnc (str): MNC of IMSI
196 opmode (Hex-str, 1 Byte): MS Operation Mode
197 ofm (Hex-str, 1 Byte): Operational Feature Monitor (OFM) aka Ciphering Indicator
Philipp Maier284ac102023-01-17 14:26:56 +0100198 path (optional list with file path e.g. ['3f00', '7f20', '6fad'])
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100199
Harald Weltec91085e2022-02-10 18:05:45 +0100200 Returns:
201 str: Return code of write operation
202 """
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100203
Harald Weltec91085e2022-02-10 18:05:45 +0100204 ad = EF_AD()
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100205
Harald Weltec91085e2022-02-10 18:05:45 +0100206 # read from card
207 raw_hex_data, sw = self._scc.read_binary(
Philipp Maier284ac102023-01-17 14:26:56 +0100208 path, length=None, offset=0)
Harald Weltec91085e2022-02-10 18:05:45 +0100209 abstract_data = ad.decode_hex(raw_hex_data)
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100210
Harald Weltec91085e2022-02-10 18:05:45 +0100211 # perform updates
212 if mnc and abstract_data['extensions']:
Philipp Maier0a8d9f02022-12-16 16:44:37 +0100213 # Note: Since we derive the length of the MNC by the string length
214 # of the mnc parameter, the caller must ensure that mnc has the
215 # correct length and is padded with zeros (if necessary).
Harald Weltec91085e2022-02-10 18:05:45 +0100216 mnclen = len(str(mnc))
Philipp Maier0a8d9f02022-12-16 16:44:37 +0100217 if mnclen > 3 or mnclen < 2:
218 raise RuntimeError('invalid length of mnc "{}", expecting 2 or 3 digits'.format(mnc))
Harald Weltec91085e2022-02-10 18:05:45 +0100219 abstract_data['extensions']['mnc_len'] = mnclen
220 if opmode:
221 opmode_num = int(opmode, 16)
222 if opmode_num in [int(v) for v in EF_AD.OP_MODE]:
223 abstract_data['ms_operation_mode'] = opmode_num
224 else:
225 raise RuntimeError('invalid opmode "{}"'.format(opmode))
226 if ofm:
227 abstract_data['ofm'] = bool(int(ofm, 16))
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100228
Harald Weltec91085e2022-02-10 18:05:45 +0100229 # write to card
230 raw_hex_data = ad.encode_hex(abstract_data)
Philipp Maier284ac102023-01-17 14:26:56 +0100231 data, sw = self._scc.update_binary(path, raw_hex_data)
Harald Weltec91085e2022-02-10 18:05:45 +0100232 return sw
Philipp Maieree908ae2019-03-21 16:21:12 +0100233
Harald Weltec91085e2022-02-10 18:05:45 +0100234 def read_spn(self):
235 (content, sw) = self._scc.read_binary(EF['SPN'])
236 if sw == '9000':
237 abstract_data = EF_SPN().decode_hex(content)
238 show_in_hplmn = abstract_data['show_in_hplmn']
239 hide_in_oplmn = abstract_data['hide_in_oplmn']
240 name = abstract_data['spn']
241 return ((name, show_in_hplmn, hide_in_oplmn), sw)
242 else:
243 return (None, sw)
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300244
Harald Weltec91085e2022-02-10 18:05:45 +0100245 def update_spn(self, name="", show_in_hplmn=False, hide_in_oplmn=False):
246 abstract_data = {
247 'hide_in_oplmn': hide_in_oplmn,
248 'show_in_hplmn': show_in_hplmn,
249 'spn': name,
250 }
251 content = EF_SPN().encode_hex(abstract_data)
252 data, sw = self._scc.update_binary(EF['SPN'], content)
253 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300254
Harald Weltec91085e2022-02-10 18:05:45 +0100255 def read_binary(self, ef, length=None, offset=0):
256 ef_path = ef in EF and EF[ef] or ef
257 return self._scc.read_binary(ef_path, length, offset)
Supreeth Herled21349a2020-04-01 08:37:47 +0200258
Harald Weltec91085e2022-02-10 18:05:45 +0100259 def read_record(self, ef, rec_no):
260 ef_path = ef in EF and EF[ef] or ef
261 return self._scc.read_record(ef_path, rec_no)
Supreeth Herlead10d662020-04-01 08:43:08 +0200262
Harald Weltec91085e2022-02-10 18:05:45 +0100263 def read_gid1(self):
264 (res, sw) = self._scc.read_binary(EF['GID1'])
265 if sw == '9000':
266 return (res, sw)
267 else:
268 return (None, sw)
Supreeth Herle98a69272020-03-18 12:14:48 +0100269
Harald Weltec91085e2022-02-10 18:05:45 +0100270 def read_msisdn(self):
271 (res, sw) = self._scc.read_record(EF['MSISDN'], 1)
272 if sw == '9000':
273 return (dec_msisdn(res), sw)
274 else:
275 return (None, sw)
Supreeth Herle6d66af62020-03-19 12:49:16 +0100276
Harald Weltec91085e2022-02-10 18:05:45 +0100277 def read_aids(self):
278 """Fetch all the AIDs present on UICC"""
279 self._aids = []
280 try:
281 # Find out how many records the EF.DIR has
282 # and store all the AIDs in the UICC
283 rec_cnt = self._scc.record_count(EF['DIR'])
284 for i in range(0, rec_cnt):
285 rec = self._scc.read_record(EF['DIR'], i + 1)
286 if (rec[0][0:2], rec[0][4:6]) == ('61', '4f') and len(rec[0]) > 12 \
287 and rec[0][8:8 + int(rec[0][6:8], 16) * 2] not in self._aids:
288 self._aids.append(rec[0][8:8 + int(rec[0][6:8], 16) * 2])
289 except Exception as e:
290 print("Can't read AIDs from SIM -- %s" % (str(e),))
291 self._aids = []
292 return self._aids
Supreeth Herlee4e98312020-03-18 11:33:14 +0100293
Harald Weltec91085e2022-02-10 18:05:45 +0100294 @staticmethod
295 def _get_aid(adf="usim") -> str:
296 aid_map = {}
297 # First (known) halves of the U/ISIM AID
298 aid_map["usim"] = "a0000000871002"
299 aid_map["isim"] = "a0000000871004"
300 adf = adf.lower()
301 if adf in aid_map:
302 return aid_map[adf]
303 return None
Philipp Maier46c61542021-11-16 16:36:50 +0100304
Harald Weltec91085e2022-02-10 18:05:45 +0100305 def _complete_aid(self, aid) -> str:
306 """find the complete version of an ADF.U/ISIM AID"""
307 # Find full AID by partial AID:
308 if is_hex(aid):
309 for aid_known in self._aids:
310 if len(aid_known) >= len(aid) and aid == aid_known[0:len(aid)]:
311 return aid_known
312 return None
Philipp Maier46c61542021-11-16 16:36:50 +0100313
Philipp Maier84902402023-02-10 18:23:36 +0100314 def adf_present(self, adf="usim") -> bool:
315 """Check if the AID of the specified ADF is present in EF.DIR (call read_aids before use)"""
316 aid = self._get_aid(adf)
317 if aid:
318 aid_full = self._complete_aid(aid)
319 if aid_full:
320 return True
321 return False
322
Harald Weltec91085e2022-02-10 18:05:45 +0100323 def select_adf_by_aid(self, adf="usim"):
324 """Select ADF.U/ISIM in the Card using its full AID"""
325 if is_hex(adf):
326 aid = adf
327 else:
328 aid = self._get_aid(adf)
329 if aid:
330 aid_full = self._complete_aid(aid)
331 if aid_full:
332 return self._scc.select_adf(aid_full)
333 else:
334 # If we cannot get the full AID, try with short AID
335 return self._scc.select_adf(aid)
336 return (None, None)
Supreeth Herlef9f3e5e2020-03-22 08:04:59 +0100337
Harald Weltec91085e2022-02-10 18:05:45 +0100338 def erase_binary(self, ef):
339 """Erase the contents of a file"""
340 len = self._scc.binary_size(ef)
341 self._scc.update_binary(ef, "ff" * len, offset=0, verify=True)
Philipp Maier5c2cc662020-05-12 16:27:12 +0200342
Harald Weltec91085e2022-02-10 18:05:45 +0100343 def erase_record(self, ef, rec_no):
344 """Erase the contents of a single record"""
345 len = self._scc.record_size(ef)
346 self._scc.update_record(ef, rec_no, "ff" * len,
347 force_len=False, verify=True)
Philipp Maier5c2cc662020-05-12 16:27:12 +0200348
Harald Weltec91085e2022-02-10 18:05:45 +0100349 def set_apdu_parameter(self, cla, sel_ctrl):
350 """Set apdu parameters (class byte and selection control bytes)"""
351 self._scc.cla_byte = cla
352 self._scc.sel_ctrl = sel_ctrl
Philipp Maier30b225f2021-10-29 16:41:46 +0200353
Harald Weltec91085e2022-02-10 18:05:45 +0100354 def get_apdu_parameter(self):
355 """Get apdu parameters (class byte and selection control bytes)"""
356 return (self._scc.cla_byte, self._scc.sel_ctrl)
357
Philipp Maier30b225f2021-10-29 16:41:46 +0200358
Philipp Maierbb73e512021-05-05 16:14:00 +0200359class UsimCard(SimCard):
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200360
Harald Weltec91085e2022-02-10 18:05:45 +0100361 name = 'USIM'
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200362
Harald Weltec91085e2022-02-10 18:05:45 +0100363 def __init__(self, ssc):
364 super(UsimCard, self).__init__(ssc)
Harald Welteca673942020-06-03 15:19:40 +0200365
Philipp Maierbda52832022-06-14 16:18:12 +0200366 # See also: ETSI TS 102 221, Table 9.3
367 self._adm_chv_num = 0xA0
368
Harald Weltec91085e2022-02-10 18:05:45 +0100369 def read_ehplmn(self):
370 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'])
371 if sw == '9000':
372 return (format_xplmn(res), sw)
373 else:
374 return (None, sw)
Harald Welteca673942020-06-03 15:19:40 +0200375
Harald Weltec91085e2022-02-10 18:05:45 +0100376 def update_ehplmn(self, mcc, mnc):
377 data = self._scc.read_binary(
378 EF_USIM_ADF_map['EHPLMN'], length=None, offset=0)
379 size = len(data[0]) // 2
380 ehplmn = enc_plmn(mcc, mnc)
381 data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], ehplmn)
382 return sw
Harald Welteca673942020-06-03 15:19:40 +0200383
Harald Weltec91085e2022-02-10 18:05:45 +0100384 def read_epdgid(self):
385 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
386 if sw == '9000':
387 try:
388 addr, addr_type = dec_addr_tlv(res)
389 except:
390 addr = None
391 addr_type = None
392 return (format_addr(addr, addr_type), sw)
393 else:
394 return (None, sw)
herlesupreethf8232db2020-09-29 10:03:06 +0200395
Harald Weltec91085e2022-02-10 18:05:45 +0100396 def update_epdgid(self, epdgid):
397 size = self._scc.binary_size(EF_USIM_ADF_map['ePDGId']) * 2
398 if len(epdgid) > 0:
399 addr_type = get_addr_type(epdgid)
400 if addr_type == None:
401 raise ValueError(
402 "Unknown ePDG Id address type or invalid address provided")
403 epdgid_tlv = rpad(enc_addr_tlv(epdgid, ('%02x' % addr_type)), size)
404 else:
405 epdgid_tlv = rpad('ff', size)
406 data, sw = self._scc.update_binary(
407 EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
408 return sw
Harald Welteca673942020-06-03 15:19:40 +0200409
Harald Weltec91085e2022-02-10 18:05:45 +0100410 def read_ePDGSelection(self):
411 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'])
412 if sw == '9000':
413 return (format_ePDGSelection(res), sw)
414 else:
415 return (None, sw)
Supreeth Herle99d55552020-03-24 13:03:43 +0100416
Harald Weltec91085e2022-02-10 18:05:45 +0100417 def update_ePDGSelection(self, mcc, mnc):
418 (res, sw) = self._scc.read_binary(
419 EF_USIM_ADF_map['ePDGSelection'], length=None, offset=0)
420 if sw == '9000' and (len(mcc) == 0 or len(mnc) == 0):
421 # Reset contents
422 # 80 - Tag value
423 (res, sw) = self._scc.update_binary(
424 EF_USIM_ADF_map['ePDGSelection'], rpad('', len(res)))
425 elif sw == '9000':
426 (res, sw) = self._scc.update_binary(
427 EF_USIM_ADF_map['ePDGSelection'], enc_ePDGSelection(res, mcc, mnc))
428 return sw
Supreeth Herlef964df42020-03-24 13:15:37 +0100429
Harald Weltec91085e2022-02-10 18:05:45 +0100430 def read_ust(self):
431 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
432 if sw == '9000':
433 # Print those which are available
434 return ([res, dec_st(res, table="usim")], sw)
435 else:
436 return ([None, None], sw)
herlesupreeth4a3580b2020-09-29 10:11:36 +0200437
Harald Weltec91085e2022-02-10 18:05:45 +0100438 def update_ust(self, service, bit=1):
439 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
440 if sw == '9000':
441 content = enc_st(res, service, bit)
442 (res, sw) = self._scc.update_binary(
443 EF_USIM_ADF_map['UST'], content)
444 return sw
445
Harald Welte6ca2fa72022-02-12 16:29:31 +0100446 def update_est(self, service, bit=1):
447 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EST'])
448 if sw == '9000':
449 content = enc_st(res, service, bit)
450 (res, sw) = self._scc.update_binary(
451 EF_USIM_ADF_map['EST'], content)
452 return sw
453
454
Supreeth Herleacc222f2020-03-24 13:26:53 +0100455
Philipp Maierbb73e512021-05-05 16:14:00 +0200456class IsimCard(SimCard):
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200457
Harald Weltec91085e2022-02-10 18:05:45 +0100458 name = 'ISIM'
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200459
Harald Weltec91085e2022-02-10 18:05:45 +0100460 def __init__(self, ssc):
461 super(IsimCard, self).__init__(ssc)
herlesupreethecbada92020-12-23 09:24:29 +0100462
Harald Weltec91085e2022-02-10 18:05:45 +0100463 def read_pcscf(self):
464 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['PCSCF'])
465 pcscf_recs = ""
466 for i in range(0, rec_cnt):
467 (res, sw) = self._scc.read_record(EF_ISIM_ADF_map['PCSCF'], i + 1)
468 if sw == '9000':
469 try:
470 addr, addr_type = dec_addr_tlv(res)
471 except:
472 addr = None
473 addr_type = None
474 content = format_addr(addr, addr_type)
475 pcscf_recs += "%s" % (len(content)
476 and content or '\tNot available\n')
477 else:
478 pcscf_recs += "\tP-CSCF: Can't read, response code = %s\n" % (
479 sw)
480 return pcscf_recs
Supreeth Herle5ad9aec2020-03-24 17:26:40 +0100481
Harald Weltec91085e2022-02-10 18:05:45 +0100482 def update_pcscf(self, pcscf):
483 if len(pcscf) > 0:
484 addr_type = get_addr_type(pcscf)
485 if addr_type == None:
486 raise ValueError(
487 "Unknown PCSCF address type or invalid address provided")
488 content = enc_addr_tlv(pcscf, ('%02x' % addr_type))
489 else:
490 # Just the tag value
491 content = '80'
492 rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['PCSCF'])
493 pcscf_tlv = rpad(content, rec_size_bytes*2)
494 data, sw = self._scc.update_record(
495 EF_ISIM_ADF_map['PCSCF'], 1, pcscf_tlv)
496 return sw
Supreeth Herlecf727f22020-03-24 17:32:21 +0100497
Harald Weltec91085e2022-02-10 18:05:45 +0100498 def read_domain(self):
499 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['DOMAIN'])
500 if sw == '9000':
501 # Skip the initial tag value ('80') byte and get length of contents
502 length = int(res[2:4], 16)
503 content = h2s(res[4:4+(length*2)])
504 return (content, sw)
505 else:
506 return (None, sw)
Supreeth Herle05b28072020-03-25 10:23:48 +0100507
Harald Weltec91085e2022-02-10 18:05:45 +0100508 def update_domain(self, domain=None, mcc=None, mnc=None):
509 hex_str = ""
510 if domain:
511 hex_str = s2h(domain)
512 elif mcc and mnc:
513 # MCC and MNC always has 3 digits in domain form
514 plmn_str = 'mnc' + lpad(mnc, 3, "0") + '.mcc' + lpad(mcc, 3, "0")
515 hex_str = s2h('ims.' + plmn_str + '.3gppnetwork.org')
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100516
Harald Weltec91085e2022-02-10 18:05:45 +0100517 # Build TLV
518 tlv = TLV(['80'])
519 content = tlv.build({'80': hex_str})
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100520
Harald Weltec91085e2022-02-10 18:05:45 +0100521 bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['DOMAIN'])
522 data, sw = self._scc.update_binary(
523 EF_ISIM_ADF_map['DOMAIN'], rpad(content, bin_size_bytes*2))
524 return sw
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100525
Harald Weltec91085e2022-02-10 18:05:45 +0100526 def read_impi(self):
527 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IMPI'])
528 if sw == '9000':
529 # Skip the initial tag value ('80') byte and get length of contents
530 length = int(res[2:4], 16)
531 content = h2s(res[4:4+(length*2)])
532 return (content, sw)
533 else:
534 return (None, sw)
Supreeth Herle3f67f9c2020-03-25 15:38:02 +0100535
Harald Weltec91085e2022-02-10 18:05:45 +0100536 def update_impi(self, impi=None):
537 hex_str = ""
538 if impi:
539 hex_str = s2h(impi)
540 # Build TLV
541 tlv = TLV(['80'])
542 content = tlv.build({'80': hex_str})
Supreeth Herlea5bd9682020-03-26 09:16:14 +0100543
Harald Weltec91085e2022-02-10 18:05:45 +0100544 bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['IMPI'])
545 data, sw = self._scc.update_binary(
546 EF_ISIM_ADF_map['IMPI'], rpad(content, bin_size_bytes*2))
547 return sw
Supreeth Herlea5bd9682020-03-26 09:16:14 +0100548
Harald Weltec91085e2022-02-10 18:05:45 +0100549 def read_impu(self):
550 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['IMPU'])
551 impu_recs = ""
552 for i in range(0, rec_cnt):
553 (res, sw) = self._scc.read_record(EF_ISIM_ADF_map['IMPU'], i + 1)
554 if sw == '9000':
555 # Skip the initial tag value ('80') byte and get length of contents
556 length = int(res[2:4], 16)
557 content = h2s(res[4:4+(length*2)])
558 impu_recs += "\t%s\n" % (len(content)
559 and content or 'Not available')
560 else:
561 impu_recs += "IMS public user identity: Can't read, response code = %s\n" % (
562 sw)
563 return impu_recs
Supreeth Herle0c02d8a2020-03-26 09:00:06 +0100564
Harald Weltec91085e2022-02-10 18:05:45 +0100565 def update_impu(self, impu=None):
566 hex_str = ""
567 if impu:
568 hex_str = s2h(impu)
569 # Build TLV
570 tlv = TLV(['80'])
571 content = tlv.build({'80': hex_str})
Supreeth Herlebe7007e2020-03-26 09:27:45 +0100572
Harald Weltec91085e2022-02-10 18:05:45 +0100573 rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['IMPU'])
574 impu_tlv = rpad(content, rec_size_bytes*2)
575 data, sw = self._scc.update_record(
576 EF_ISIM_ADF_map['IMPU'], 1, impu_tlv)
577 return sw
Supreeth Herlebe7007e2020-03-26 09:27:45 +0100578
Harald Weltec91085e2022-02-10 18:05:45 +0100579 def read_iari(self):
580 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['UICCIARI'])
581 uiari_recs = ""
582 for i in range(0, rec_cnt):
583 (res, sw) = self._scc.read_record(
584 EF_ISIM_ADF_map['UICCIARI'], i + 1)
585 if sw == '9000':
586 # Skip the initial tag value ('80') byte and get length of contents
587 length = int(res[2:4], 16)
588 content = h2s(res[4:4+(length*2)])
589 uiari_recs += "\t%s\n" % (len(content)
590 and content or 'Not available')
591 else:
592 uiari_recs += "UICC IARI: Can't read, response code = %s\n" % (
593 sw)
594 return uiari_recs
595
Harald Welte6ca2fa72022-02-12 16:29:31 +0100596 def update_ist(self, service, bit=1):
597 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IST'])
598 if sw == '9000':
599 content = enc_st(res, service, bit)
600 (res, sw) = self._scc.update_binary(
601 EF_ISIM_ADF_map['IST'], content)
602 return sw
603
Sylvain Munaut76504e02010-12-07 00:24:32 +0100604
Philipp Maierbb73e512021-05-05 16:14:00 +0200605class MagicSimBase(abc.ABC, SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100606 """
607 Theses cards uses several record based EFs to store the provider infos,
608 each possible provider uses a specific record number in each EF. The
609 indexes used are ( where N is the number of providers supported ) :
610 - [2 .. N+1] for the operator name
611 - [1 .. N] for the programmable EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100612
Harald Weltec91085e2022-02-10 18:05:45 +0100613 * 3f00/7f4d/8f0c : Operator Name
Sylvain Munaut76504e02010-12-07 00:24:32 +0100614
Harald Weltec91085e2022-02-10 18:05:45 +0100615 bytes 0-15 : provider name, padded with 0xff
616 byte 16 : length of the provider name
617 byte 17 : 01 for valid records, 00 otherwise
Sylvain Munaut76504e02010-12-07 00:24:32 +0100618
Harald Weltec91085e2022-02-10 18:05:45 +0100619 * 3f00/7f4d/8f0d : Programmable Binary EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100620
Harald Weltec91085e2022-02-10 18:05:45 +0100621 * 3f00/7f4d/8f0e : Programmable Record EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100622
Harald Weltec91085e2022-02-10 18:05:45 +0100623 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100624
Harald Weltec91085e2022-02-10 18:05:45 +0100625 _files = {} # type: Dict[str, Tuple[str, int, bool]]
626 _ki_file = None # type: Optional[str]
Vadim Yanitskiy03c67f72021-05-02 02:10:39 +0200627
Harald Weltec91085e2022-02-10 18:05:45 +0100628 @classmethod
629 def autodetect(kls, scc):
630 try:
631 for p, l, t in kls._files.values():
632 if not t:
633 continue
634 if scc.record_size(['3f00', '7f4d', p]) != l:
635 return None
636 except:
637 return None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100638
Harald Weltec91085e2022-02-10 18:05:45 +0100639 return kls(scc)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100640
Harald Weltec91085e2022-02-10 18:05:45 +0100641 def _get_count(self):
642 """
643 Selects the file and returns the total number of entries
644 and entry size
645 """
646 f = self._files['name']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100647
Harald Weltec91085e2022-02-10 18:05:45 +0100648 r = self._scc.select_path(['3f00', '7f4d', f[0]])
649 rec_len = int(r[-1][28:30], 16)
650 tlen = int(r[-1][4:8], 16)
651 rec_cnt = (tlen // rec_len) - 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100652
Harald Weltec91085e2022-02-10 18:05:45 +0100653 if (rec_cnt < 1) or (rec_len != f[1]):
654 raise RuntimeError('Bad card type')
Sylvain Munaut76504e02010-12-07 00:24:32 +0100655
Harald Weltec91085e2022-02-10 18:05:45 +0100656 return rec_cnt
Sylvain Munaut76504e02010-12-07 00:24:32 +0100657
Harald Weltec91085e2022-02-10 18:05:45 +0100658 def program(self, p):
659 # Go to dir
660 self._scc.select_path(['3f00', '7f4d'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100661
Harald Weltec91085e2022-02-10 18:05:45 +0100662 # Home PLMN in PLMN_Sel format
663 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100664
Harald Weltec91085e2022-02-10 18:05:45 +0100665 # Operator name ( 3f00/7f4d/8f0c )
666 self._scc.update_record(self._files['name'][0], 2,
667 rpad(b2h(p['name']), 32) + ('%02x' %
668 len(p['name'])) + '01'
669 )
Sylvain Munaut76504e02010-12-07 00:24:32 +0100670
Harald Weltec91085e2022-02-10 18:05:45 +0100671 # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
672 v = ''
Sylvain Munaut76504e02010-12-07 00:24:32 +0100673
Harald Weltec91085e2022-02-10 18:05:45 +0100674 # inline Ki
675 if self._ki_file is None:
676 v += p['ki']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100677
Harald Weltec91085e2022-02-10 18:05:45 +0100678 # ICCID
679 v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100680
Harald Weltec91085e2022-02-10 18:05:45 +0100681 # IMSI
682 v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100683
Harald Weltec91085e2022-02-10 18:05:45 +0100684 # Ki
685 if self._ki_file:
686 v += self._ki_file + '10' + p['ki']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100687
Harald Weltec91085e2022-02-10 18:05:45 +0100688 # PLMN_Sel
689 v += '6f30' + '18' + rpad(hplmn, 36)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100690
Harald Weltec91085e2022-02-10 18:05:45 +0100691 # ACC
692 # This doesn't work with "fake" SuperSIM cards,
693 # but will hopefully work with real SuperSIMs.
694 if p.get('acc') is not None:
695 v += '6f78' + '02' + lpad(p['acc'], 4)
Alexander Chemeris21885242013-07-02 16:56:55 +0400696
Harald Weltec91085e2022-02-10 18:05:45 +0100697 self._scc.update_record(self._files['b_ef'][0], 1,
698 rpad(v, self._files['b_ef'][1]*2)
699 )
Sylvain Munaut76504e02010-12-07 00:24:32 +0100700
Harald Weltec91085e2022-02-10 18:05:45 +0100701 # SMSP ( 3f00/7f4d/8f0e )
702 # FIXME
Sylvain Munaut76504e02010-12-07 00:24:32 +0100703
Harald Weltec91085e2022-02-10 18:05:45 +0100704 # Write PLMN_Sel forcefully as well
705 r = self._scc.select_path(['3f00', '7f20', '6f30'])
706 tl = int(r[-1][4:8], 16)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100707
Harald Weltec91085e2022-02-10 18:05:45 +0100708 hplmn = enc_plmn(p['mcc'], p['mnc'])
709 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100710
Harald Weltec91085e2022-02-10 18:05:45 +0100711 def erase(self):
712 # Dummy
713 df = {}
714 for k, v in self._files.items():
715 ofs = 1
716 fv = v[1] * 'ff'
717 if k == 'name':
718 ofs = 2
719 fv = fv[0:-4] + '0000'
720 df[v[0]] = (fv, ofs)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100721
Harald Weltec91085e2022-02-10 18:05:45 +0100722 # Write
723 for n in range(0, self._get_count()):
724 for k, (msg, ofs) in df.items():
725 self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100726
727
Vadim Yanitskiy85302d62021-05-02 02:18:42 +0200728class SuperSim(MagicSimBase):
Sylvain Munaut76504e02010-12-07 00:24:32 +0100729
Harald Weltec91085e2022-02-10 18:05:45 +0100730 name = 'supersim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100731
Harald Weltec91085e2022-02-10 18:05:45 +0100732 _files = {
733 'name': ('8f0c', 18, True),
734 'b_ef': ('8f0d', 74, True),
735 'r_ef': ('8f0e', 50, True),
736 }
Sylvain Munaut76504e02010-12-07 00:24:32 +0100737
Harald Weltec91085e2022-02-10 18:05:45 +0100738 _ki_file = None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100739
740
Vadim Yanitskiy85302d62021-05-02 02:18:42 +0200741class MagicSim(MagicSimBase):
Sylvain Munaut76504e02010-12-07 00:24:32 +0100742
Harald Weltec91085e2022-02-10 18:05:45 +0100743 name = 'magicsim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100744
Harald Weltec91085e2022-02-10 18:05:45 +0100745 _files = {
746 'name': ('8f0c', 18, True),
747 'b_ef': ('8f0d', 130, True),
748 'r_ef': ('8f0e', 102, False),
749 }
Sylvain Munaut76504e02010-12-07 00:24:32 +0100750
Harald Weltec91085e2022-02-10 18:05:45 +0100751 _ki_file = '6f1b'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100752
753
Philipp Maierbb73e512021-05-05 16:14:00 +0200754class FakeMagicSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100755 """
756 Theses cards have a record based EF 3f00/000c that contains the provider
757 information. See the program method for its format. The records go from
758 1 to N.
759 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100760
Harald Weltec91085e2022-02-10 18:05:45 +0100761 name = 'fakemagicsim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100762
Harald Weltec91085e2022-02-10 18:05:45 +0100763 @classmethod
764 def autodetect(kls, scc):
765 try:
766 if scc.record_size(['3f00', '000c']) != 0x5a:
767 return None
768 except:
769 return None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100770
Harald Weltec91085e2022-02-10 18:05:45 +0100771 return kls(scc)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100772
Harald Weltec91085e2022-02-10 18:05:45 +0100773 def _get_infos(self):
774 """
775 Selects the file and returns the total number of entries
776 and entry size
777 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100778
Harald Weltec91085e2022-02-10 18:05:45 +0100779 r = self._scc.select_path(['3f00', '000c'])
780 rec_len = int(r[-1][28:30], 16)
781 tlen = int(r[-1][4:8], 16)
782 rec_cnt = (tlen // rec_len) - 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100783
Harald Weltec91085e2022-02-10 18:05:45 +0100784 if (rec_cnt < 1) or (rec_len != 0x5a):
785 raise RuntimeError('Bad card type')
Sylvain Munaut76504e02010-12-07 00:24:32 +0100786
Harald Weltec91085e2022-02-10 18:05:45 +0100787 return rec_cnt, rec_len
Sylvain Munaut76504e02010-12-07 00:24:32 +0100788
Harald Weltec91085e2022-02-10 18:05:45 +0100789 def program(self, p):
790 # Home PLMN
791 r = self._scc.select_path(['3f00', '7f20', '6f30'])
792 tl = int(r[-1][4:8], 16)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100793
Harald Weltec91085e2022-02-10 18:05:45 +0100794 hplmn = enc_plmn(p['mcc'], p['mnc'])
795 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100796
Harald Weltec91085e2022-02-10 18:05:45 +0100797 # Get total number of entries and entry size
798 rec_cnt, rec_len = self._get_infos()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100799
Harald Weltec91085e2022-02-10 18:05:45 +0100800 # Set first entry
801 entry = (
802 '81' + # 1b Status: Valid & Active
803 rpad(s2h(p['name'][0:14]), 28) + # 14b Entry Name
804 enc_iccid(p['iccid']) + # 10b ICCID
805 enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
806 p['ki'] + # 16b Ki
807 lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
808 )
809 self._scc.update_record('000c', 1, entry)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100810
Harald Weltec91085e2022-02-10 18:05:45 +0100811 def erase(self):
812 # Get total number of entries and entry size
813 rec_cnt, rec_len = self._get_infos()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100814
Harald Weltec91085e2022-02-10 18:05:45 +0100815 # Erase all entries
816 entry = 'ff' * rec_len
817 for i in range(0, rec_cnt):
818 self._scc.update_record('000c', 1+i, entry)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100819
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200820
Philipp Maierbb73e512021-05-05 16:14:00 +0200821class GrcardSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100822 """
823 Greencard (grcard.cn) HZCOS GSM SIM
824 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
825 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
826 """
Harald Welte3156d902011-03-22 21:48:19 +0100827
Harald Weltec91085e2022-02-10 18:05:45 +0100828 name = 'grcardsim'
Harald Welte3156d902011-03-22 21:48:19 +0100829
Harald Weltec91085e2022-02-10 18:05:45 +0100830 @classmethod
831 def autodetect(kls, scc):
832 return None
Harald Welte3156d902011-03-22 21:48:19 +0100833
Harald Weltec91085e2022-02-10 18:05:45 +0100834 def program(self, p):
835 # We don't really know yet what ADM PIN 4 is about
836 #self._scc.verify_chv(4, h2b("4444444444444444"))
Harald Welte3156d902011-03-22 21:48:19 +0100837
Harald Weltec91085e2022-02-10 18:05:45 +0100838 # Authenticate using ADM PIN 5
839 if p['pin_adm']:
840 pin = h2b(p['pin_adm'])
841 else:
842 pin = h2b("4444444444444444")
843 self._scc.verify_chv(5, pin)
Harald Welte3156d902011-03-22 21:48:19 +0100844
Harald Weltec91085e2022-02-10 18:05:45 +0100845 # EF.ICCID
846 r = self._scc.select_path(['3f00', '2fe2'])
847 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100848
Harald Weltec91085e2022-02-10 18:05:45 +0100849 # EF.IMSI
850 r = self._scc.select_path(['3f00', '7f20', '6f07'])
851 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100852
Harald Weltec91085e2022-02-10 18:05:45 +0100853 # EF.ACC
854 if p.get('acc') is not None:
855 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100856
Harald Weltec91085e2022-02-10 18:05:45 +0100857 # EF.SMSP
858 if p.get('smsp'):
859 r = self._scc.select_path(['3f00', '7f10', '6f42'])
860 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100861
Harald Weltec91085e2022-02-10 18:05:45 +0100862 # Set the Ki using proprietary command
863 pdu = '80d4020010' + p['ki']
864 data, sw = self._scc._tp.send_apdu(pdu)
Harald Welte3156d902011-03-22 21:48:19 +0100865
Harald Weltec91085e2022-02-10 18:05:45 +0100866 # EF.HPLMN
867 r = self._scc.select_path(['3f00', '7f20', '6f30'])
868 size = int(r[-1][4:8], 16)
869 hplmn = enc_plmn(p['mcc'], p['mnc'])
870 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
Harald Welte3156d902011-03-22 21:48:19 +0100871
Harald Weltec91085e2022-02-10 18:05:45 +0100872 # EF.SPN (Service Provider Name)
873 r = self._scc.select_path(['3f00', '7f20', '6f30'])
874 size = int(r[-1][4:8], 16)
875 # FIXME
Harald Welte3156d902011-03-22 21:48:19 +0100876
Harald Weltec91085e2022-02-10 18:05:45 +0100877 # FIXME: EF.MSISDN
Harald Welte3156d902011-03-22 21:48:19 +0100878
Sylvain Munaut76504e02010-12-07 00:24:32 +0100879
Harald Weltee10394b2011-12-07 12:34:14 +0100880class SysmoSIMgr1(GrcardSim):
Harald Weltec91085e2022-02-10 18:05:45 +0100881 """
882 sysmocom sysmoSIM-GR1
883 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
884 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
885 """
886 name = 'sysmosim-gr1'
Harald Weltee10394b2011-12-07 12:34:14 +0100887
Harald Weltec91085e2022-02-10 18:05:45 +0100888 @classmethod
889 def autodetect(kls, scc):
890 try:
891 # Look for ATR
892 if scc.get_atr() == toBytes("3B 99 18 00 11 88 22 33 44 55 66 77 60"):
893 return kls(scc)
894 except:
895 return None
896 return None
897
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200898
Harald Welteca673942020-06-03 15:19:40 +0200899class SysmoUSIMgr1(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100900 """
901 sysmocom sysmoUSIM-GR1
902 """
903 name = 'sysmoUSIM-GR1'
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100904
Harald Weltec91085e2022-02-10 18:05:45 +0100905 @classmethod
906 def autodetect(kls, scc):
907 # TODO: Access the ATR
908 return None
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100909
Harald Weltec91085e2022-02-10 18:05:45 +0100910 def program(self, p):
911 # TODO: check if verify_chv could be used or what it needs
912 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
913 # Unlock the card..
914 data, sw = self._scc._tp.send_apdu_checksw(
915 "0020000A083332323133323332")
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100916
Harald Weltec91085e2022-02-10 18:05:45 +0100917 # TODO: move into SimCardCommands
918 par = (p['ki'] + # 16b K
919 p['opc'] + # 32b OPC
920 enc_iccid(p['iccid']) + # 10b ICCID
921 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
922 )
923 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100924
Sylvain Munaut053c8952013-07-02 15:12:32 +0200925
Philipp Maierbb73e512021-05-05 16:14:00 +0200926class SysmoSIMgr2(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100927 """
928 sysmocom sysmoSIM-GR2
929 """
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100930
Harald Weltec91085e2022-02-10 18:05:45 +0100931 name = 'sysmoSIM-GR2'
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100932
Harald Weltec91085e2022-02-10 18:05:45 +0100933 @classmethod
934 def autodetect(kls, scc):
935 try:
936 # Look for ATR
937 if scc.get_atr() == toBytes("3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68"):
938 return kls(scc)
939 except:
940 return None
941 return None
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100942
Harald Weltec91085e2022-02-10 18:05:45 +0100943 def program(self, p):
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100944
Harald Weltec91085e2022-02-10 18:05:45 +0100945 # select MF
946 r = self._scc.select_path(['3f00'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200947
Harald Weltec91085e2022-02-10 18:05:45 +0100948 # authenticate as SUPER ADM using default key
949 self._scc.verify_chv(0x0b, h2b("3838383838383838"))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100950
Harald Weltec91085e2022-02-10 18:05:45 +0100951 # set ADM pin using proprietary command
952 # INS: D4
953 # P1: 3A for PIN, 3B for PUK
954 # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
955 # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
956 if p['pin_adm']:
957 pin = h2b(p['pin_adm'])
958 else:
959 pin = h2b("4444444444444444")
Jan Balkec3ebd332015-01-26 12:22:55 +0100960
Harald Weltec91085e2022-02-10 18:05:45 +0100961 pdu = 'A0D43A0508' + b2h(pin)
962 data, sw = self._scc._tp.send_apdu(pdu)
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200963
Harald Weltec91085e2022-02-10 18:05:45 +0100964 # authenticate as ADM (enough to write file, and can set PINs)
Jan Balkec3ebd332015-01-26 12:22:55 +0100965
Harald Weltec91085e2022-02-10 18:05:45 +0100966 self._scc.verify_chv(0x05, pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100967
Harald Weltec91085e2022-02-10 18:05:45 +0100968 # write EF.ICCID
969 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100970
Harald Weltec91085e2022-02-10 18:05:45 +0100971 # select DF_GSM
972 r = self._scc.select_path(['7f20'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200973
Harald Weltec91085e2022-02-10 18:05:45 +0100974 # write EF.IMSI
975 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100976
Harald Weltec91085e2022-02-10 18:05:45 +0100977 # write EF.ACC
978 if p.get('acc') is not None:
979 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100980
Harald Weltec91085e2022-02-10 18:05:45 +0100981 # get size and write EF.HPLMN
982 r = self._scc.select_path(['6f30'])
983 size = int(r[-1][4:8], 16)
984 hplmn = enc_plmn(p['mcc'], p['mnc'])
985 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100986
Harald Weltec91085e2022-02-10 18:05:45 +0100987 # set COMP128 version 0 in proprietary file
988 data, sw = self._scc.update_binary('0001', '001000')
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100989
Harald Weltec91085e2022-02-10 18:05:45 +0100990 # set Ki in proprietary file
991 data, sw = self._scc.update_binary('0001', p['ki'], 3)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100992
Harald Weltec91085e2022-02-10 18:05:45 +0100993 # select DF_TELECOM
994 r = self._scc.select_path(['3f00', '7f10'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200995
Harald Weltec91085e2022-02-10 18:05:45 +0100996 # write EF.SMSP
997 if p.get('smsp'):
998 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100999
Sylvain Munaut2fc205c2013-12-23 17:22:56 +01001000
Harald Welteca673942020-06-03 15:19:40 +02001001class SysmoUSIMSJS1(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001002 """
1003 sysmocom sysmoUSIM-SJS1
1004 """
Jan Balke3e840672015-01-26 15:36:27 +01001005
Harald Weltec91085e2022-02-10 18:05:45 +01001006 name = 'sysmoUSIM-SJS1'
Jan Balke3e840672015-01-26 15:36:27 +01001007
Harald Weltec91085e2022-02-10 18:05:45 +01001008 def __init__(self, ssc):
1009 super(SysmoUSIMSJS1, self).__init__(ssc)
1010 self._scc.cla_byte = "00"
1011 self._scc.sel_ctrl = "0004" # request an FCP
Jan Balke3e840672015-01-26 15:36:27 +01001012
Harald Weltec91085e2022-02-10 18:05:45 +01001013 @classmethod
1014 def autodetect(kls, scc):
1015 try:
1016 # Look for ATR
1017 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"):
1018 return kls(scc)
1019 except:
1020 return None
1021 return None
Jan Balke3e840672015-01-26 15:36:27 +01001022
Harald Weltec91085e2022-02-10 18:05:45 +01001023 def verify_adm(self, key):
1024 # authenticate as ADM using default key (written on the card..)
1025 if not key:
1026 raise ValueError(
1027 "Please provide a PIN-ADM as there is no default one")
1028 (res, sw) = self._scc.verify_chv(0x0A, key)
1029 return sw
Harald Weltea6704252021-01-08 20:19:11 +01001030
Harald Weltec91085e2022-02-10 18:05:45 +01001031 def program(self, p):
1032 self.verify_adm(h2b(p['pin_adm']))
Jan Balke3e840672015-01-26 15:36:27 +01001033
Harald Weltec91085e2022-02-10 18:05:45 +01001034 # select MF
1035 r = self._scc.select_path(['3f00'])
Jan Balke3e840672015-01-26 15:36:27 +01001036
Harald Weltec91085e2022-02-10 18:05:45 +01001037 # write EF.ICCID
1038 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Philipp Maiere9604882017-03-21 17:24:31 +01001039
Harald Weltec91085e2022-02-10 18:05:45 +01001040 # select DF_GSM
1041 r = self._scc.select_path(['7f20'])
Jan Balke3e840672015-01-26 15:36:27 +01001042
Harald Weltec91085e2022-02-10 18:05:45 +01001043 # set Ki in proprietary file
1044 data, sw = self._scc.update_binary('00FF', p['ki'])
Jan Balke3e840672015-01-26 15:36:27 +01001045
Harald Weltec91085e2022-02-10 18:05:45 +01001046 # set OPc in proprietary file
1047 if 'opc' in p:
1048 content = "01" + p['opc']
1049 data, sw = self._scc.update_binary('00F7', content)
Jan Balke3e840672015-01-26 15:36:27 +01001050
Harald Weltec91085e2022-02-10 18:05:45 +01001051 # set Service Provider Name
1052 if p.get('name') is not None:
1053 self.update_spn(p['name'], True, True)
Supreeth Herle7947d922019-06-08 07:50:53 +02001054
Harald Weltec91085e2022-02-10 18:05:45 +01001055 if p.get('acc') is not None:
1056 self.update_acc(p['acc'])
Supreeth Herlec8796a32019-12-23 12:23:42 +01001057
Harald Weltec91085e2022-02-10 18:05:45 +01001058 # write EF.IMSI
1059 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Jan Balke3e840672015-01-26 15:36:27 +01001060
Harald Weltec91085e2022-02-10 18:05:45 +01001061 # EF.PLMNsel
1062 if p.get('mcc') and p.get('mnc'):
1063 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1064 if sw != '9000':
1065 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001066
Harald Weltec91085e2022-02-10 18:05:45 +01001067 # EF.PLMNwAcT
1068 if p.get('mcc') and p.get('mnc'):
1069 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1070 if sw != '9000':
1071 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001072
Harald Weltec91085e2022-02-10 18:05:45 +01001073 # EF.OPLMNwAcT
1074 if p.get('mcc') and p.get('mnc'):
1075 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1076 if sw != '9000':
1077 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001078
Harald Weltec91085e2022-02-10 18:05:45 +01001079 # EF.HPLMNwAcT
1080 if p.get('mcc') and p.get('mnc'):
1081 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1082 if sw != '9000':
1083 print("Programming HPLMNwAcT failed with code %s" % sw)
Supreeth Herlef442fb42020-01-21 12:47:32 +01001084
Harald Weltec91085e2022-02-10 18:05:45 +01001085 # EF.AD
1086 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1087 if p.get('mcc') and p.get('mnc'):
1088 mnc = p['mnc']
1089 else:
1090 mnc = None
1091 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1092 if sw != '9000':
1093 print("Programming AD failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001094
Harald Weltec91085e2022-02-10 18:05:45 +01001095 # EF.SMSP
1096 if p.get('smsp'):
1097 r = self._scc.select_path(['3f00', '7f10'])
1098 data, sw = self._scc.update_record(
1099 '6f42', 1, lpad(p['smsp'], 104), force_len=True)
Jan Balke3e840672015-01-26 15:36:27 +01001100
Harald Weltec91085e2022-02-10 18:05:45 +01001101 # EF.MSISDN
1102 # TODO: Alpha Identifier (currently 'ff'O * 20)
1103 # TODO: Capability/Configuration1 Record Identifier
1104 # TODO: Extension1 Record Identifier
1105 if p.get('msisdn') is not None:
1106 msisdn = enc_msisdn(p['msisdn'])
1107 data = 'ff' * 20 + msisdn
Supreeth Herle5a541012019-12-22 08:59:16 +01001108
Harald Weltec91085e2022-02-10 18:05:45 +01001109 r = self._scc.select_path(['3f00', '7f10'])
1110 data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
Supreeth Herle5a541012019-12-22 08:59:16 +01001111
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001112
herlesupreeth4a3580b2020-09-29 10:11:36 +02001113class FairwavesSIM(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001114 """
1115 FairwavesSIM
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001116
Harald Weltec91085e2022-02-10 18:05:45 +01001117 The SIM card is operating according to the standard.
1118 For Ki/OP/OPC programming the following files are additionally open for writing:
1119 3F00/7F20/FF01 – OP/OPC:
1120 byte 1 = 0x01, bytes 2-17: OPC;
1121 byte 1 = 0x00, bytes 2-17: OP;
1122 3F00/7F20/FF02: Ki
1123 """
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001124
Harald Weltec91085e2022-02-10 18:05:45 +01001125 name = 'Fairwaves-SIM'
1126 # Propriatary files
1127 _EF_num = {
1128 'Ki': 'FF02',
1129 'OP/OPC': 'FF01',
1130 }
1131 _EF = {
1132 'Ki': DF['GSM']+[_EF_num['Ki']],
1133 'OP/OPC': DF['GSM']+[_EF_num['OP/OPC']],
1134 }
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001135
Harald Weltec91085e2022-02-10 18:05:45 +01001136 def __init__(self, ssc):
1137 super(FairwavesSIM, self).__init__(ssc)
1138 self._adm_chv_num = 0x11
1139 self._adm2_chv_num = 0x12
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001140
Harald Weltec91085e2022-02-10 18:05:45 +01001141 @classmethod
1142 def autodetect(kls, scc):
1143 try:
1144 # Look for ATR
1145 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"):
1146 return kls(scc)
1147 except:
1148 return None
1149 return None
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001150
Harald Weltec91085e2022-02-10 18:05:45 +01001151 def verify_adm2(self, key):
1152 '''
1153 Authenticate with ADM2 key.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001154
Harald Weltec91085e2022-02-10 18:05:45 +01001155 Fairwaves SIM cards support hierarchical key structure and ADM2 key
1156 is a key which has access to proprietary files (Ki and OP/OPC).
1157 That said, ADM key inherits permissions of ADM2 key and thus we rarely
1158 need ADM2 key per se.
1159 '''
1160 (res, sw) = self._scc.verify_chv(self._adm2_chv_num, key)
1161 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001162
Harald Weltec91085e2022-02-10 18:05:45 +01001163 def read_ki(self):
1164 """
1165 Read Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001166
Harald Weltec91085e2022-02-10 18:05:45 +01001167 Requires ADM1 access level
1168 """
1169 return self._scc.read_binary(self._EF['Ki'])
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001170
Harald Weltec91085e2022-02-10 18:05:45 +01001171 def update_ki(self, ki):
1172 """
1173 Set Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001174
Harald Weltec91085e2022-02-10 18:05:45 +01001175 Requires ADM1 access level
1176 """
1177 data, sw = self._scc.update_binary(self._EF['Ki'], ki)
1178 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001179
Harald Weltec91085e2022-02-10 18:05:45 +01001180 def read_op_opc(self):
1181 """
1182 Read Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001183
Harald Weltec91085e2022-02-10 18:05:45 +01001184 Requires ADM1 access level
1185 """
1186 (ef, sw) = self._scc.read_binary(self._EF['OP/OPC'])
1187 type = 'OP' if ef[0:2] == '00' else 'OPC'
1188 return ((type, ef[2:]), sw)
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001189
Harald Weltec91085e2022-02-10 18:05:45 +01001190 def update_op(self, op):
1191 """
1192 Set OP in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001193
Harald Weltec91085e2022-02-10 18:05:45 +01001194 Requires ADM1 access level
1195 """
1196 content = '00' + op
1197 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
1198 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001199
Harald Weltec91085e2022-02-10 18:05:45 +01001200 def update_opc(self, opc):
1201 """
1202 Set OPC in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001203
Harald Weltec91085e2022-02-10 18:05:45 +01001204 Requires ADM1 access level
1205 """
1206 content = '01' + opc
1207 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
1208 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001209
Harald Weltec91085e2022-02-10 18:05:45 +01001210 def program(self, p):
1211 # For some reason the card programming only works when the card
1212 # is handled as a classic SIM, even though it is an USIM, so we
1213 # reconfigure the class byte and the select control field on
1214 # the fly. When the programming is done the original values are
1215 # restored.
1216 cla_byte_orig = self._scc.cla_byte
1217 sel_ctrl_orig = self._scc.sel_ctrl
1218 self._scc.cla_byte = "a0"
1219 self._scc.sel_ctrl = "0000"
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001220
Harald Weltec91085e2022-02-10 18:05:45 +01001221 try:
1222 self._program(p)
1223 finally:
1224 # restore original cla byte and sel ctrl
1225 self._scc.cla_byte = cla_byte_orig
1226 self._scc.sel_ctrl = sel_ctrl_orig
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001227
Harald Weltec91085e2022-02-10 18:05:45 +01001228 def _program(self, p):
1229 # authenticate as ADM1
1230 if not p['pin_adm']:
1231 raise ValueError(
1232 "Please provide a PIN-ADM as there is no default one")
1233 self.verify_adm(h2b(p['pin_adm']))
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001234
Harald Weltec91085e2022-02-10 18:05:45 +01001235 # TODO: Set operator name
1236 if p.get('smsp') is not None:
1237 sw = self.update_smsp(p['smsp'])
1238 if sw != '9000':
1239 print("Programming SMSP failed with code %s" % sw)
1240 # This SIM doesn't support changing ICCID
1241 if p.get('mcc') is not None and p.get('mnc') is not None:
1242 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1243 if sw != '9000':
1244 print("Programming MCC/MNC failed with code %s" % sw)
1245 if p.get('imsi') is not None:
1246 sw = self.update_imsi(p['imsi'])
1247 if sw != '9000':
1248 print("Programming IMSI failed with code %s" % sw)
1249 if p.get('ki') is not None:
1250 sw = self.update_ki(p['ki'])
1251 if sw != '9000':
1252 print("Programming Ki failed with code %s" % sw)
1253 if p.get('opc') is not None:
1254 sw = self.update_opc(p['opc'])
1255 if sw != '9000':
1256 print("Programming OPC failed with code %s" % sw)
1257 if p.get('acc') is not None:
1258 sw = self.update_acc(p['acc'])
1259 if sw != '9000':
1260 print("Programming ACC failed with code %s" % sw)
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001261
1262
Philipp Maierbb73e512021-05-05 16:14:00 +02001263class OpenCellsSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001264 """
1265 OpenCellsSim
Todd Neal9eeadfc2018-04-25 15:36:29 -05001266
Harald Weltec91085e2022-02-10 18:05:45 +01001267 """
Todd Neal9eeadfc2018-04-25 15:36:29 -05001268
Harald Weltec91085e2022-02-10 18:05:45 +01001269 name = 'OpenCells-SIM'
Todd Neal9eeadfc2018-04-25 15:36:29 -05001270
Harald Weltec91085e2022-02-10 18:05:45 +01001271 def __init__(self, ssc):
1272 super(OpenCellsSim, self).__init__(ssc)
1273 self._adm_chv_num = 0x0A
Todd Neal9eeadfc2018-04-25 15:36:29 -05001274
Harald Weltec91085e2022-02-10 18:05:45 +01001275 @classmethod
1276 def autodetect(kls, scc):
1277 try:
1278 # Look for ATR
1279 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"):
1280 return kls(scc)
1281 except:
1282 return None
1283 return None
Todd Neal9eeadfc2018-04-25 15:36:29 -05001284
Harald Weltec91085e2022-02-10 18:05:45 +01001285 def program(self, p):
1286 if not p['pin_adm']:
1287 raise ValueError(
1288 "Please provide a PIN-ADM as there is no default one")
1289 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001290
Harald Weltec91085e2022-02-10 18:05:45 +01001291 # select MF
1292 r = self._scc.select_path(['3f00'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001293
Harald Weltec91085e2022-02-10 18:05:45 +01001294 # write EF.ICCID
1295 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001296
Harald Weltec91085e2022-02-10 18:05:45 +01001297 r = self._scc.select_path(['7ff0'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001298
Harald Weltec91085e2022-02-10 18:05:45 +01001299 # set Ki in proprietary file
1300 data, sw = self._scc.update_binary('FF02', p['ki'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001301
Harald Weltec91085e2022-02-10 18:05:45 +01001302 # set OPC in proprietary file
1303 data, sw = self._scc.update_binary('FF01', p['opc'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001304
Harald Weltec91085e2022-02-10 18:05:45 +01001305 # select DF_GSM
1306 r = self._scc.select_path(['7f20'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001307
Harald Weltec91085e2022-02-10 18:05:45 +01001308 # write EF.IMSI
1309 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001310
Todd Neal9eeadfc2018-04-25 15:36:29 -05001311
herlesupreeth4a3580b2020-09-29 10:11:36 +02001312class WavemobileSim(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001313 """
1314 WavemobileSim
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001315
Harald Weltec91085e2022-02-10 18:05:45 +01001316 """
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001317
Harald Weltec91085e2022-02-10 18:05:45 +01001318 name = 'Wavemobile-SIM'
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001319
Harald Weltec91085e2022-02-10 18:05:45 +01001320 def __init__(self, ssc):
1321 super(WavemobileSim, self).__init__(ssc)
1322 self._adm_chv_num = 0x0A
1323 self._scc.cla_byte = "00"
1324 self._scc.sel_ctrl = "0004" # request an FCP
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001325
Harald Weltec91085e2022-02-10 18:05:45 +01001326 @classmethod
1327 def autodetect(kls, scc):
1328 try:
1329 # Look for ATR
1330 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"):
1331 return kls(scc)
1332 except:
1333 return None
1334 return None
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001335
Harald Weltec91085e2022-02-10 18:05:45 +01001336 def program(self, p):
1337 if not p['pin_adm']:
1338 raise ValueError(
1339 "Please provide a PIN-ADM as there is no default one")
1340 self.verify_adm(h2b(p['pin_adm']))
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001341
Harald Weltec91085e2022-02-10 18:05:45 +01001342 # EF.ICCID
1343 # TODO: Add programming of the ICCID
1344 if p.get('iccid'):
1345 print(
1346 "Warning: Programming of the ICCID is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001347
Philipp Maierde0cf162023-01-03 13:29:45 +01001348 # KI (Presumably a proprietary file)
Harald Weltec91085e2022-02-10 18:05:45 +01001349 # TODO: Add programming of KI
1350 if p.get('ki'):
1351 print(
1352 "Warning: Programming of the KI is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001353
Philipp Maierde0cf162023-01-03 13:29:45 +01001354 # OPc (Presumably a proprietary file)
Harald Weltec91085e2022-02-10 18:05:45 +01001355 # TODO: Add programming of OPc
1356 if p.get('opc'):
1357 print(
1358 "Warning: Programming of the OPc is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001359
Harald Weltec91085e2022-02-10 18:05:45 +01001360 # EF.SMSP
1361 if p.get('smsp'):
1362 sw = self.update_smsp(p['smsp'])
1363 if sw != '9000':
1364 print("Programming SMSP failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001365
Harald Weltec91085e2022-02-10 18:05:45 +01001366 # EF.IMSI
1367 if p.get('imsi'):
1368 sw = self.update_imsi(p['imsi'])
1369 if sw != '9000':
1370 print("Programming IMSI failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001371
Harald Weltec91085e2022-02-10 18:05:45 +01001372 # EF.ACC
1373 if p.get('acc'):
1374 sw = self.update_acc(p['acc'])
1375 if sw != '9000':
1376 print("Programming ACC failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001377
Harald Weltec91085e2022-02-10 18:05:45 +01001378 # EF.PLMNsel
1379 if p.get('mcc') and p.get('mnc'):
1380 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1381 if sw != '9000':
1382 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001383
Harald Weltec91085e2022-02-10 18:05:45 +01001384 # EF.PLMNwAcT
1385 if p.get('mcc') and p.get('mnc'):
1386 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1387 if sw != '9000':
1388 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001389
Harald Weltec91085e2022-02-10 18:05:45 +01001390 # EF.OPLMNwAcT
1391 if p.get('mcc') and p.get('mnc'):
1392 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1393 if sw != '9000':
1394 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001395
Harald Weltec91085e2022-02-10 18:05:45 +01001396 # EF.AD
1397 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1398 if p.get('mcc') and p.get('mnc'):
1399 mnc = p['mnc']
1400 else:
1401 mnc = None
1402 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1403 if sw != '9000':
1404 print("Programming AD failed with code %s" % sw)
Philipp Maier6e507a72019-04-01 16:33:48 +02001405
Harald Weltec91085e2022-02-10 18:05:45 +01001406 return None
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001407
Todd Neal9eeadfc2018-04-25 15:36:29 -05001408
herlesupreethb0c7d122020-12-23 09:25:46 +01001409class SysmoISIMSJA2(UsimCard, IsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001410 """
1411 sysmocom sysmoISIM-SJA2
1412 """
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001413
Harald Weltec91085e2022-02-10 18:05:45 +01001414 name = 'sysmoISIM-SJA2'
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001415
Harald Weltec91085e2022-02-10 18:05:45 +01001416 def __init__(self, ssc):
1417 super(SysmoISIMSJA2, self).__init__(ssc)
1418 self._scc.cla_byte = "00"
1419 self._scc.sel_ctrl = "0004" # request an FCP
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001420
Harald Weltec91085e2022-02-10 18:05:45 +01001421 @classmethod
1422 def autodetect(kls, scc):
1423 try:
1424 # Try card model #1
1425 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9"
1426 if scc.get_atr() == toBytes(atr):
1427 return kls(scc)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001428
Harald Weltec91085e2022-02-10 18:05:45 +01001429 # Try card model #2
1430 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2"
1431 if scc.get_atr() == toBytes(atr):
1432 return kls(scc)
Philipp Maierb3e11ea2020-03-11 12:32:44 +01001433
Harald Weltec91085e2022-02-10 18:05:45 +01001434 # Try card model #3
1435 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"
1436 if scc.get_atr() == toBytes(atr):
1437 return kls(scc)
1438 except:
1439 return None
1440 return None
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001441
Harald Weltec91085e2022-02-10 18:05:45 +01001442 def verify_adm(self, key):
1443 # authenticate as ADM using default key (written on the card..)
1444 if not key:
1445 raise ValueError(
1446 "Please provide a PIN-ADM as there is no default one")
1447 (res, sw) = self._scc.verify_chv(0x0A, key)
1448 return sw
Harald Weltea6704252021-01-08 20:19:11 +01001449
Harald Weltec91085e2022-02-10 18:05:45 +01001450 def program(self, p):
1451 self.verify_adm(h2b(p['pin_adm']))
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001452
Philipp Maier84902402023-02-10 18:23:36 +01001453 # Populate AIDs
1454 self.read_aids()
1455
Harald Weltec91085e2022-02-10 18:05:45 +01001456 # This type of card does not allow to reprogram the ICCID.
1457 # Reprogramming the ICCID would mess up the card os software
1458 # license management, so the ICCID must be kept at its factory
1459 # setting!
1460 if p.get('iccid'):
1461 print(
1462 "Warning: Programming of the ICCID is not implemented for this type of card.")
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001463
Harald Weltec91085e2022-02-10 18:05:45 +01001464 # select DF_GSM
1465 self._scc.select_path(['7f20'])
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001466
Harald Weltec91085e2022-02-10 18:05:45 +01001467 # set Service Provider Name
1468 if p.get('name') is not None:
1469 self.update_spn(p['name'], True, True)
Robert Falkenberg54595362021-04-06 12:04:34 +02001470
Harald Weltec91085e2022-02-10 18:05:45 +01001471 # write EF.IMSI
1472 if p.get('imsi'):
1473 self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001474
Harald Weltec91085e2022-02-10 18:05:45 +01001475 # EF.PLMNsel
1476 if p.get('mcc') and p.get('mnc'):
1477 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1478 if sw != '9000':
1479 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001480
Harald Weltec91085e2022-02-10 18:05:45 +01001481 # EF.PLMNwAcT
1482 if p.get('mcc') and p.get('mnc'):
1483 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1484 if sw != '9000':
1485 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001486
Harald Weltec91085e2022-02-10 18:05:45 +01001487 # EF.OPLMNwAcT
1488 if p.get('mcc') and p.get('mnc'):
1489 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1490 if sw != '9000':
1491 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001492
Harald Weltec91085e2022-02-10 18:05:45 +01001493 # EF.HPLMNwAcT
1494 if p.get('mcc') and p.get('mnc'):
1495 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1496 if sw != '9000':
1497 print("Programming HPLMNwAcT failed with code %s" % sw)
Harald Welte32f0d412020-05-05 17:35:57 +02001498
Harald Weltec91085e2022-02-10 18:05:45 +01001499 # EF.AD
1500 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1501 if p.get('mcc') and p.get('mnc'):
1502 mnc = p['mnc']
1503 else:
1504 mnc = None
1505 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1506 if sw != '9000':
1507 print("Programming AD failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001508
Harald Weltec91085e2022-02-10 18:05:45 +01001509 # EF.SMSP
1510 if p.get('smsp'):
1511 r = self._scc.select_path(['3f00', '7f10'])
1512 data, sw = self._scc.update_record(
1513 '6f42', 1, lpad(p['smsp'], 104), force_len=True)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001514
Harald Weltec91085e2022-02-10 18:05:45 +01001515 # EF.MSISDN
1516 # TODO: Alpha Identifier (currently 'ff'O * 20)
1517 # TODO: Capability/Configuration1 Record Identifier
1518 # TODO: Extension1 Record Identifier
1519 if p.get('msisdn') is not None:
1520 msisdn = enc_msisdn(p['msisdn'])
1521 content = 'ff' * 20 + msisdn
Supreeth Herlec6019232020-03-26 10:00:45 +01001522
Harald Weltec91085e2022-02-10 18:05:45 +01001523 r = self._scc.select_path(['3f00', '7f10'])
1524 data, sw = self._scc.update_record(
1525 '6F40', 1, content, force_len=True)
Supreeth Herlec6019232020-03-26 10:00:45 +01001526
Harald Weltec91085e2022-02-10 18:05:45 +01001527 # EF.ACC
1528 if p.get('acc'):
1529 sw = self.update_acc(p['acc'])
1530 if sw != '9000':
1531 print("Programming ACC failed with code %s" % sw)
Supreeth Herlea97944b2020-03-26 10:03:25 +01001532
Harald Weltec91085e2022-02-10 18:05:45 +01001533 # update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
1534 # hard linked to EF-USIM_AUTH_KEY)
1535 self._scc.select_path(['3f00'])
1536 self._scc.select_path(['a515'])
1537 if p.get('ki'):
1538 self._scc.update_binary('6f20', p['ki'], 1)
1539 if p.get('opc'):
1540 self._scc.update_binary('6f20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001541
Harald Weltec91085e2022-02-10 18:05:45 +01001542 # update EF-USIM_AUTH_KEY in ADF.ISIM
Philipp Maier84902402023-02-10 18:23:36 +01001543 if self.adf_present("isim"):
1544 self.select_adf_by_aid(adf="isim")
1545
Harald Weltec91085e2022-02-10 18:05:45 +01001546 if p.get('ki'):
1547 self._scc.update_binary('af20', p['ki'], 1)
1548 if p.get('opc'):
1549 self._scc.update_binary('af20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001550
Harald Weltec91085e2022-02-10 18:05:45 +01001551 # update EF.P-CSCF in ADF.ISIM
1552 if self.file_exists(EF_ISIM_ADF_map['PCSCF']):
1553 if p.get('pcscf'):
1554 sw = self.update_pcscf(p['pcscf'])
1555 else:
1556 sw = self.update_pcscf("")
1557 if sw != '9000':
1558 print("Programming P-CSCF failed with code %s" % sw)
Supreeth Herlecf727f22020-03-24 17:32:21 +01001559
Harald Weltec91085e2022-02-10 18:05:45 +01001560 # update EF.DOMAIN in ADF.ISIM
1561 if self.file_exists(EF_ISIM_ADF_map['DOMAIN']):
1562 if p.get('ims_hdomain'):
1563 sw = self.update_domain(domain=p['ims_hdomain'])
1564 else:
1565 sw = self.update_domain()
Supreeth Herlecf727f22020-03-24 17:32:21 +01001566
Harald Weltec91085e2022-02-10 18:05:45 +01001567 if sw != '9000':
1568 print(
1569 "Programming Home Network Domain Name failed with code %s" % sw)
Supreeth Herle79f43dd2020-03-25 11:43:19 +01001570
Harald Weltec91085e2022-02-10 18:05:45 +01001571 # update EF.IMPI in ADF.ISIM
1572 # TODO: Validate IMPI input
1573 if self.file_exists(EF_ISIM_ADF_map['IMPI']):
1574 if p.get('impi'):
1575 sw = self.update_impi(p['impi'])
1576 else:
1577 sw = self.update_impi()
1578 if sw != '9000':
1579 print("Programming IMPI failed with code %s" % sw)
Supreeth Herle79f43dd2020-03-25 11:43:19 +01001580
Harald Weltec91085e2022-02-10 18:05:45 +01001581 # update EF.IMPU in ADF.ISIM
1582 # TODO: Validate IMPU input
1583 # Support multiple IMPU if there is enough space
1584 if self.file_exists(EF_ISIM_ADF_map['IMPU']):
1585 if p.get('impu'):
1586 sw = self.update_impu(p['impu'])
1587 else:
1588 sw = self.update_impu()
1589 if sw != '9000':
1590 print("Programming IMPU failed with code %s" % sw)
Supreeth Herlea5bd9682020-03-26 09:16:14 +01001591
Philipp Maier84902402023-02-10 18:23:36 +01001592 if self.adf_present("usim"):
1593 self.select_adf_by_aid(adf="usim")
1594
Philipp Maier284ac102023-01-17 14:26:56 +01001595 # EF.AD in ADF.USIM
1596 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1597 if p.get('mcc') and p.get('mnc'):
1598 mnc = p['mnc']
1599 else:
1600 mnc = None
1601 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'),
1602 path=EF_USIM_ADF_map['AD'])
1603 if sw != '9000':
1604 print("Programming AD failed with code %s" % sw)
1605
Harald Weltec91085e2022-02-10 18:05:45 +01001606 # update EF-USIM_AUTH_KEY in ADF.USIM
1607 if p.get('ki'):
1608 self._scc.update_binary('af20', p['ki'], 1)
1609 if p.get('opc'):
1610 self._scc.update_binary('af20', p['opc'], 17)
Supreeth Herlebe7007e2020-03-26 09:27:45 +01001611
Harald Weltec91085e2022-02-10 18:05:45 +01001612 # update EF.EHPLMN in ADF.USIM
1613 if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
1614 if p.get('mcc') and p.get('mnc'):
1615 sw = self.update_ehplmn(p['mcc'], p['mnc'])
1616 if sw != '9000':
1617 print("Programming EHPLMN failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001618
Harald Weltec91085e2022-02-10 18:05:45 +01001619 # update EF.ePDGId in ADF.USIM
1620 if self.file_exists(EF_USIM_ADF_map['ePDGId']):
1621 if p.get('epdgid'):
1622 sw = self.update_epdgid(p['epdgid'])
1623 else:
1624 sw = self.update_epdgid("")
1625 if sw != '9000':
1626 print("Programming ePDGId failed with code %s" % sw)
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001627
Harald Weltec91085e2022-02-10 18:05:45 +01001628 # update EF.ePDGSelection in ADF.USIM
1629 if self.file_exists(EF_USIM_ADF_map['ePDGSelection']):
1630 if p.get('epdgSelection'):
1631 epdg_plmn = p['epdgSelection']
1632 sw = self.update_ePDGSelection(
1633 epdg_plmn[:3], epdg_plmn[3:])
1634 else:
1635 sw = self.update_ePDGSelection("", "")
1636 if sw != '9000':
1637 print("Programming ePDGSelection failed with code %s" % sw)
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001638
Harald Weltec91085e2022-02-10 18:05:45 +01001639 # After successfully programming EF.ePDGId and EF.ePDGSelection,
1640 # Set service 106 and 107 as available in EF.UST
1641 # Disable service 95, 99, 115 if ISIM application is present
1642 if self.file_exists(EF_USIM_ADF_map['UST']):
1643 if p.get('epdgSelection') and p.get('epdgid'):
1644 sw = self.update_ust(106, 1)
1645 if sw != '9000':
1646 print("Programming UST failed with code %s" % sw)
1647 sw = self.update_ust(107, 1)
1648 if sw != '9000':
1649 print("Programming UST failed with code %s" % sw)
Supreeth Herlef964df42020-03-24 13:15:37 +01001650
Harald Weltec91085e2022-02-10 18:05:45 +01001651 sw = self.update_ust(95, 0)
1652 if sw != '9000':
1653 print("Programming UST failed with code %s" % sw)
1654 sw = self.update_ust(99, 0)
1655 if sw != '9000':
1656 print("Programming UST failed with code %s" % sw)
1657 sw = self.update_ust(115, 0)
1658 if sw != '9000':
1659 print("Programming UST failed with code %s" % sw)
Supreeth Herlef964df42020-03-24 13:15:37 +01001660
Harald Weltec91085e2022-02-10 18:05:45 +01001661 return
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001662
Harald Welte0489ae62023-05-24 10:28:34 +02001663class SysmoISIMSJA5(SysmoISIMSJA2):
1664 """
1665 sysmocom sysmoISIM-SJA5
1666 """
1667
1668 name = 'sysmoISIM-SJA5'
1669
1670 @classmethod
1671 def autodetect(kls, scc):
1672 try:
1673 # Try card model #1 (9FJ)
1674 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 51 CC"
1675 if scc.get_atr() == toBytes(atr):
1676 return kls(scc)
1677 # Try card model #2 (SLM17)
1678 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 65 F8"
1679 if scc.get_atr() == toBytes(atr):
1680 return kls(scc)
1681 # Try card model #3 (9FV)
1682 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 59 C4"
1683 if scc.get_atr() == toBytes(atr):
1684 return kls(scc)
1685 except:
1686 return None
1687 return None
1688
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001689
Matan Perelmanc296cb52023-05-11 12:49:17 +03001690class GialerSim(UsimCard):
1691 """
1692 Gialer sim cards (www.gialer.com).
1693 """
1694 name = 'gialersim'
1695
1696 def __init__(self, ssc):
1697 super().__init__(ssc)
1698 self._program_handlers = {
1699 'iccid': self.update_iccid,
1700 'imsi': self.update_imsi,
1701 'acc': self.update_acc,
1702 'smsp': self.update_smsp,
1703 'ki': self.update_ki,
1704 'opc': self.update_opc,
1705 }
1706
1707 @classmethod
1708 def autodetect(cls, scc):
1709 try:
1710 # Look for ATR
1711 if scc.get_atr() == toBytes('3B 9F 95 80 1F C7 80 31 A0 73 B6 A1 00 67 CF 32 15 CA 9C D7 09 20'):
1712 return cls(scc)
1713 except:
1714 return None
1715 return None
1716
1717 def program(self, p):
1718 # Authenticate
1719 self._scc.verify_chv(0xc, h2b('3834373936313533'))
1720 for handler in self._program_handlers:
1721 if p.get(handler) is not None:
1722 self._program_handlers[handler](p[handler])
1723
1724 mcc = p.get('mcc')
1725 mnc = p.get('mnc')
1726 has_plmn = mcc is not None and mnc is not None
1727 # EF.HPLMN
1728 if has_plmn:
1729 self.update_hplmn_act(mcc, mnc)
1730
1731 # EF.AD
1732 if has_plmn or (p.get('opmode') is not None):
1733 self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1734
1735 def update_smsp(self, smsp):
1736 data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 80))
1737 return sw
1738
1739 def update_ki(self, ki):
1740 self._scc.select_path(['3f00', '0001'])
1741 self._scc.update_binary('0001', ki)
1742
1743 def update_opc(self, opc):
1744 self._scc.select_path(['3f00', '6002'])
1745 # No idea why the '01' is required
1746 self._scc.update_binary('6002', '01' + opc)
1747
1748
Todd Neal9eeadfc2018-04-25 15:36:29 -05001749# In order for autodetection ...
Harald Weltec91085e2022-02-10 18:05:45 +01001750_cards_classes = [FakeMagicSim, SuperSim, MagicSim, GrcardSim,
1751 SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
Harald Welte0489ae62023-05-24 10:28:34 +02001752 FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2,
Matan Perelmanc296cb52023-05-11 12:49:17 +03001753 SysmoISIMSJA5, GialerSim]
Harald Weltec91085e2022-02-10 18:05:45 +01001754
Alexander Chemeris8ad124a2018-01-10 14:17:55 +09001755
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001756def card_detect(ctype, scc):
Harald Weltec91085e2022-02-10 18:05:45 +01001757 # Detect type if needed
1758 card = None
1759 ctypes = dict([(kls.name, kls) for kls in _cards_classes])
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001760
Harald Weltec91085e2022-02-10 18:05:45 +01001761 if ctype == "auto":
1762 for kls in _cards_classes:
1763 card = kls.autodetect(scc)
1764 if card:
1765 print("Autodetected card type: %s" % card.name)
1766 card.reset()
1767 break
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001768
Harald Weltec91085e2022-02-10 18:05:45 +01001769 if card is None:
1770 print("Autodetection failed")
1771 return None
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001772
Harald Weltec91085e2022-02-10 18:05:45 +01001773 elif ctype in ctypes:
1774 card = ctypes[ctype](scc)
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001775
Harald Weltec91085e2022-02-10 18:05:45 +01001776 else:
1777 raise ValueError("Unknown card type: %s" % ctype)
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001778
Harald Weltec91085e2022-02-10 18:05:45 +01001779 return card