blob: d3a43f39e3fae7b247ce0024e4b21c01ba4620e5 [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
Matan Perelman777ee9e2023-05-14 08:58:50 +0300384 def read_fplmn(self):
385 res, sw = self._scc.read_binary(EF_USIM_ADF_map['FPLMN'])
386 if sw == '9000':
387 return format_xplmn(res), sw
388 else:
389 return None, sw
390
391 def update_fplmn(self, fplmn):
392 self._scc.select_file('3f00')
393 self.select_adf_by_aid('USIM')
394 size = self._scc.binary_size(EF_USIM_ADF_map['FPLMN'])
395 encoded = ''.join([enc_plmn(plmn[:3], plmn[3:]) for plmn in fplmn])
396 encoded = rpad(encoded, size)
397 data, sw = self._scc.update_binary(EF_USIM_ADF_map['FPLMN'], encoded)
398 return sw
399
Harald Weltec91085e2022-02-10 18:05:45 +0100400 def read_epdgid(self):
401 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
402 if sw == '9000':
403 try:
404 addr, addr_type = dec_addr_tlv(res)
405 except:
406 addr = None
407 addr_type = None
408 return (format_addr(addr, addr_type), sw)
409 else:
410 return (None, sw)
herlesupreethf8232db2020-09-29 10:03:06 +0200411
Harald Weltec91085e2022-02-10 18:05:45 +0100412 def update_epdgid(self, epdgid):
413 size = self._scc.binary_size(EF_USIM_ADF_map['ePDGId']) * 2
414 if len(epdgid) > 0:
415 addr_type = get_addr_type(epdgid)
416 if addr_type == None:
417 raise ValueError(
418 "Unknown ePDG Id address type or invalid address provided")
419 epdgid_tlv = rpad(enc_addr_tlv(epdgid, ('%02x' % addr_type)), size)
420 else:
421 epdgid_tlv = rpad('ff', size)
422 data, sw = self._scc.update_binary(
423 EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
424 return sw
Harald Welteca673942020-06-03 15:19:40 +0200425
Harald Weltec91085e2022-02-10 18:05:45 +0100426 def read_ePDGSelection(self):
427 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'])
428 if sw == '9000':
429 return (format_ePDGSelection(res), sw)
430 else:
431 return (None, sw)
Supreeth Herle99d55552020-03-24 13:03:43 +0100432
Harald Weltec91085e2022-02-10 18:05:45 +0100433 def update_ePDGSelection(self, mcc, mnc):
434 (res, sw) = self._scc.read_binary(
435 EF_USIM_ADF_map['ePDGSelection'], length=None, offset=0)
436 if sw == '9000' and (len(mcc) == 0 or len(mnc) == 0):
437 # Reset contents
438 # 80 - Tag value
439 (res, sw) = self._scc.update_binary(
440 EF_USIM_ADF_map['ePDGSelection'], rpad('', len(res)))
441 elif sw == '9000':
442 (res, sw) = self._scc.update_binary(
443 EF_USIM_ADF_map['ePDGSelection'], enc_ePDGSelection(res, mcc, mnc))
444 return sw
Supreeth Herlef964df42020-03-24 13:15:37 +0100445
Harald Weltec91085e2022-02-10 18:05:45 +0100446 def read_ust(self):
447 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
448 if sw == '9000':
449 # Print those which are available
450 return ([res, dec_st(res, table="usim")], sw)
451 else:
452 return ([None, None], sw)
herlesupreeth4a3580b2020-09-29 10:11:36 +0200453
Harald Weltec91085e2022-02-10 18:05:45 +0100454 def update_ust(self, service, bit=1):
455 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
456 if sw == '9000':
457 content = enc_st(res, service, bit)
458 (res, sw) = self._scc.update_binary(
459 EF_USIM_ADF_map['UST'], content)
460 return sw
461
Harald Welte6ca2fa72022-02-12 16:29:31 +0100462 def update_est(self, service, bit=1):
463 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EST'])
464 if sw == '9000':
465 content = enc_st(res, service, bit)
466 (res, sw) = self._scc.update_binary(
467 EF_USIM_ADF_map['EST'], content)
468 return sw
469
470
Supreeth Herleacc222f2020-03-24 13:26:53 +0100471
Philipp Maierbb73e512021-05-05 16:14:00 +0200472class IsimCard(SimCard):
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200473
Harald Weltec91085e2022-02-10 18:05:45 +0100474 name = 'ISIM'
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200475
Harald Weltec91085e2022-02-10 18:05:45 +0100476 def __init__(self, ssc):
477 super(IsimCard, self).__init__(ssc)
herlesupreethecbada92020-12-23 09:24:29 +0100478
Harald Weltec91085e2022-02-10 18:05:45 +0100479 def read_pcscf(self):
480 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['PCSCF'])
481 pcscf_recs = ""
482 for i in range(0, rec_cnt):
483 (res, sw) = self._scc.read_record(EF_ISIM_ADF_map['PCSCF'], i + 1)
484 if sw == '9000':
485 try:
486 addr, addr_type = dec_addr_tlv(res)
487 except:
488 addr = None
489 addr_type = None
490 content = format_addr(addr, addr_type)
491 pcscf_recs += "%s" % (len(content)
492 and content or '\tNot available\n')
493 else:
494 pcscf_recs += "\tP-CSCF: Can't read, response code = %s\n" % (
495 sw)
496 return pcscf_recs
Supreeth Herle5ad9aec2020-03-24 17:26:40 +0100497
Harald Weltec91085e2022-02-10 18:05:45 +0100498 def update_pcscf(self, pcscf):
499 if len(pcscf) > 0:
500 addr_type = get_addr_type(pcscf)
501 if addr_type == None:
502 raise ValueError(
503 "Unknown PCSCF address type or invalid address provided")
504 content = enc_addr_tlv(pcscf, ('%02x' % addr_type))
505 else:
506 # Just the tag value
507 content = '80'
508 rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['PCSCF'])
509 pcscf_tlv = rpad(content, rec_size_bytes*2)
510 data, sw = self._scc.update_record(
511 EF_ISIM_ADF_map['PCSCF'], 1, pcscf_tlv)
512 return sw
Supreeth Herlecf727f22020-03-24 17:32:21 +0100513
Harald Weltec91085e2022-02-10 18:05:45 +0100514 def read_domain(self):
515 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['DOMAIN'])
516 if sw == '9000':
517 # Skip the initial tag value ('80') byte and get length of contents
518 length = int(res[2:4], 16)
519 content = h2s(res[4:4+(length*2)])
520 return (content, sw)
521 else:
522 return (None, sw)
Supreeth Herle05b28072020-03-25 10:23:48 +0100523
Harald Weltec91085e2022-02-10 18:05:45 +0100524 def update_domain(self, domain=None, mcc=None, mnc=None):
525 hex_str = ""
526 if domain:
527 hex_str = s2h(domain)
528 elif mcc and mnc:
529 # MCC and MNC always has 3 digits in domain form
530 plmn_str = 'mnc' + lpad(mnc, 3, "0") + '.mcc' + lpad(mcc, 3, "0")
531 hex_str = s2h('ims.' + plmn_str + '.3gppnetwork.org')
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100532
Harald Weltec91085e2022-02-10 18:05:45 +0100533 # Build TLV
534 tlv = TLV(['80'])
535 content = tlv.build({'80': hex_str})
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100536
Harald Weltec91085e2022-02-10 18:05:45 +0100537 bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['DOMAIN'])
538 data, sw = self._scc.update_binary(
539 EF_ISIM_ADF_map['DOMAIN'], rpad(content, bin_size_bytes*2))
540 return sw
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100541
Harald Weltec91085e2022-02-10 18:05:45 +0100542 def read_impi(self):
543 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IMPI'])
544 if sw == '9000':
545 # Skip the initial tag value ('80') byte and get length of contents
546 length = int(res[2:4], 16)
547 content = h2s(res[4:4+(length*2)])
548 return (content, sw)
549 else:
550 return (None, sw)
Supreeth Herle3f67f9c2020-03-25 15:38:02 +0100551
Harald Weltec91085e2022-02-10 18:05:45 +0100552 def update_impi(self, impi=None):
553 hex_str = ""
554 if impi:
555 hex_str = s2h(impi)
556 # Build TLV
557 tlv = TLV(['80'])
558 content = tlv.build({'80': hex_str})
Supreeth Herlea5bd9682020-03-26 09:16:14 +0100559
Harald Weltec91085e2022-02-10 18:05:45 +0100560 bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['IMPI'])
561 data, sw = self._scc.update_binary(
562 EF_ISIM_ADF_map['IMPI'], rpad(content, bin_size_bytes*2))
563 return sw
Supreeth Herlea5bd9682020-03-26 09:16:14 +0100564
Harald Weltec91085e2022-02-10 18:05:45 +0100565 def read_impu(self):
566 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['IMPU'])
567 impu_recs = ""
568 for i in range(0, rec_cnt):
569 (res, sw) = self._scc.read_record(EF_ISIM_ADF_map['IMPU'], i + 1)
570 if sw == '9000':
571 # Skip the initial tag value ('80') byte and get length of contents
572 length = int(res[2:4], 16)
573 content = h2s(res[4:4+(length*2)])
574 impu_recs += "\t%s\n" % (len(content)
575 and content or 'Not available')
576 else:
577 impu_recs += "IMS public user identity: Can't read, response code = %s\n" % (
578 sw)
579 return impu_recs
Supreeth Herle0c02d8a2020-03-26 09:00:06 +0100580
Harald Weltec91085e2022-02-10 18:05:45 +0100581 def update_impu(self, impu=None):
582 hex_str = ""
583 if impu:
584 hex_str = s2h(impu)
585 # Build TLV
586 tlv = TLV(['80'])
587 content = tlv.build({'80': hex_str})
Supreeth Herlebe7007e2020-03-26 09:27:45 +0100588
Harald Weltec91085e2022-02-10 18:05:45 +0100589 rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['IMPU'])
590 impu_tlv = rpad(content, rec_size_bytes*2)
591 data, sw = self._scc.update_record(
592 EF_ISIM_ADF_map['IMPU'], 1, impu_tlv)
593 return sw
Supreeth Herlebe7007e2020-03-26 09:27:45 +0100594
Harald Weltec91085e2022-02-10 18:05:45 +0100595 def read_iari(self):
596 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['UICCIARI'])
597 uiari_recs = ""
598 for i in range(0, rec_cnt):
599 (res, sw) = self._scc.read_record(
600 EF_ISIM_ADF_map['UICCIARI'], i + 1)
601 if sw == '9000':
602 # Skip the initial tag value ('80') byte and get length of contents
603 length = int(res[2:4], 16)
604 content = h2s(res[4:4+(length*2)])
605 uiari_recs += "\t%s\n" % (len(content)
606 and content or 'Not available')
607 else:
608 uiari_recs += "UICC IARI: Can't read, response code = %s\n" % (
609 sw)
610 return uiari_recs
611
Harald Welte6ca2fa72022-02-12 16:29:31 +0100612 def update_ist(self, service, bit=1):
613 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IST'])
614 if sw == '9000':
615 content = enc_st(res, service, bit)
616 (res, sw) = self._scc.update_binary(
617 EF_ISIM_ADF_map['IST'], content)
618 return sw
619
Sylvain Munaut76504e02010-12-07 00:24:32 +0100620
Philipp Maierbb73e512021-05-05 16:14:00 +0200621class MagicSimBase(abc.ABC, SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100622 """
623 Theses cards uses several record based EFs to store the provider infos,
624 each possible provider uses a specific record number in each EF. The
625 indexes used are ( where N is the number of providers supported ) :
626 - [2 .. N+1] for the operator name
627 - [1 .. N] for the programmable EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100628
Harald Weltec91085e2022-02-10 18:05:45 +0100629 * 3f00/7f4d/8f0c : Operator Name
Sylvain Munaut76504e02010-12-07 00:24:32 +0100630
Harald Weltec91085e2022-02-10 18:05:45 +0100631 bytes 0-15 : provider name, padded with 0xff
632 byte 16 : length of the provider name
633 byte 17 : 01 for valid records, 00 otherwise
Sylvain Munaut76504e02010-12-07 00:24:32 +0100634
Harald Weltec91085e2022-02-10 18:05:45 +0100635 * 3f00/7f4d/8f0d : Programmable Binary EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100636
Harald Weltec91085e2022-02-10 18:05:45 +0100637 * 3f00/7f4d/8f0e : Programmable Record EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100638
Harald Weltec91085e2022-02-10 18:05:45 +0100639 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100640
Harald Weltec91085e2022-02-10 18:05:45 +0100641 _files = {} # type: Dict[str, Tuple[str, int, bool]]
642 _ki_file = None # type: Optional[str]
Vadim Yanitskiy03c67f72021-05-02 02:10:39 +0200643
Harald Weltec91085e2022-02-10 18:05:45 +0100644 @classmethod
645 def autodetect(kls, scc):
646 try:
647 for p, l, t in kls._files.values():
648 if not t:
649 continue
650 if scc.record_size(['3f00', '7f4d', p]) != l:
651 return None
652 except:
653 return None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100654
Harald Weltec91085e2022-02-10 18:05:45 +0100655 return kls(scc)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100656
Harald Weltec91085e2022-02-10 18:05:45 +0100657 def _get_count(self):
658 """
659 Selects the file and returns the total number of entries
660 and entry size
661 """
662 f = self._files['name']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100663
Harald Weltec91085e2022-02-10 18:05:45 +0100664 r = self._scc.select_path(['3f00', '7f4d', f[0]])
665 rec_len = int(r[-1][28:30], 16)
666 tlen = int(r[-1][4:8], 16)
667 rec_cnt = (tlen // rec_len) - 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100668
Harald Weltec91085e2022-02-10 18:05:45 +0100669 if (rec_cnt < 1) or (rec_len != f[1]):
670 raise RuntimeError('Bad card type')
Sylvain Munaut76504e02010-12-07 00:24:32 +0100671
Harald Weltec91085e2022-02-10 18:05:45 +0100672 return rec_cnt
Sylvain Munaut76504e02010-12-07 00:24:32 +0100673
Harald Weltec91085e2022-02-10 18:05:45 +0100674 def program(self, p):
675 # Go to dir
676 self._scc.select_path(['3f00', '7f4d'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100677
Harald Weltec91085e2022-02-10 18:05:45 +0100678 # Home PLMN in PLMN_Sel format
679 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100680
Harald Weltec91085e2022-02-10 18:05:45 +0100681 # Operator name ( 3f00/7f4d/8f0c )
682 self._scc.update_record(self._files['name'][0], 2,
683 rpad(b2h(p['name']), 32) + ('%02x' %
684 len(p['name'])) + '01'
685 )
Sylvain Munaut76504e02010-12-07 00:24:32 +0100686
Harald Weltec91085e2022-02-10 18:05:45 +0100687 # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
688 v = ''
Sylvain Munaut76504e02010-12-07 00:24:32 +0100689
Harald Weltec91085e2022-02-10 18:05:45 +0100690 # inline Ki
691 if self._ki_file is None:
692 v += p['ki']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100693
Harald Weltec91085e2022-02-10 18:05:45 +0100694 # ICCID
695 v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100696
Harald Weltec91085e2022-02-10 18:05:45 +0100697 # IMSI
698 v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100699
Harald Weltec91085e2022-02-10 18:05:45 +0100700 # Ki
701 if self._ki_file:
702 v += self._ki_file + '10' + p['ki']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100703
Harald Weltec91085e2022-02-10 18:05:45 +0100704 # PLMN_Sel
705 v += '6f30' + '18' + rpad(hplmn, 36)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100706
Harald Weltec91085e2022-02-10 18:05:45 +0100707 # ACC
708 # This doesn't work with "fake" SuperSIM cards,
709 # but will hopefully work with real SuperSIMs.
710 if p.get('acc') is not None:
711 v += '6f78' + '02' + lpad(p['acc'], 4)
Alexander Chemeris21885242013-07-02 16:56:55 +0400712
Harald Weltec91085e2022-02-10 18:05:45 +0100713 self._scc.update_record(self._files['b_ef'][0], 1,
714 rpad(v, self._files['b_ef'][1]*2)
715 )
Sylvain Munaut76504e02010-12-07 00:24:32 +0100716
Harald Weltec91085e2022-02-10 18:05:45 +0100717 # SMSP ( 3f00/7f4d/8f0e )
718 # FIXME
Sylvain Munaut76504e02010-12-07 00:24:32 +0100719
Harald Weltec91085e2022-02-10 18:05:45 +0100720 # Write PLMN_Sel forcefully as well
721 r = self._scc.select_path(['3f00', '7f20', '6f30'])
722 tl = int(r[-1][4:8], 16)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100723
Harald Weltec91085e2022-02-10 18:05:45 +0100724 hplmn = enc_plmn(p['mcc'], p['mnc'])
725 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100726
Harald Weltec91085e2022-02-10 18:05:45 +0100727 def erase(self):
728 # Dummy
729 df = {}
730 for k, v in self._files.items():
731 ofs = 1
732 fv = v[1] * 'ff'
733 if k == 'name':
734 ofs = 2
735 fv = fv[0:-4] + '0000'
736 df[v[0]] = (fv, ofs)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100737
Harald Weltec91085e2022-02-10 18:05:45 +0100738 # Write
739 for n in range(0, self._get_count()):
740 for k, (msg, ofs) in df.items():
741 self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100742
743
Vadim Yanitskiy85302d62021-05-02 02:18:42 +0200744class SuperSim(MagicSimBase):
Sylvain Munaut76504e02010-12-07 00:24:32 +0100745
Harald Weltec91085e2022-02-10 18:05:45 +0100746 name = 'supersim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100747
Harald Weltec91085e2022-02-10 18:05:45 +0100748 _files = {
749 'name': ('8f0c', 18, True),
750 'b_ef': ('8f0d', 74, True),
751 'r_ef': ('8f0e', 50, True),
752 }
Sylvain Munaut76504e02010-12-07 00:24:32 +0100753
Harald Weltec91085e2022-02-10 18:05:45 +0100754 _ki_file = None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100755
756
Vadim Yanitskiy85302d62021-05-02 02:18:42 +0200757class MagicSim(MagicSimBase):
Sylvain Munaut76504e02010-12-07 00:24:32 +0100758
Harald Weltec91085e2022-02-10 18:05:45 +0100759 name = 'magicsim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100760
Harald Weltec91085e2022-02-10 18:05:45 +0100761 _files = {
762 'name': ('8f0c', 18, True),
763 'b_ef': ('8f0d', 130, True),
764 'r_ef': ('8f0e', 102, False),
765 }
Sylvain Munaut76504e02010-12-07 00:24:32 +0100766
Harald Weltec91085e2022-02-10 18:05:45 +0100767 _ki_file = '6f1b'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100768
769
Philipp Maierbb73e512021-05-05 16:14:00 +0200770class FakeMagicSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100771 """
772 Theses cards have a record based EF 3f00/000c that contains the provider
773 information. See the program method for its format. The records go from
774 1 to N.
775 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100776
Harald Weltec91085e2022-02-10 18:05:45 +0100777 name = 'fakemagicsim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100778
Harald Weltec91085e2022-02-10 18:05:45 +0100779 @classmethod
780 def autodetect(kls, scc):
781 try:
782 if scc.record_size(['3f00', '000c']) != 0x5a:
783 return None
784 except:
785 return None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100786
Harald Weltec91085e2022-02-10 18:05:45 +0100787 return kls(scc)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100788
Harald Weltec91085e2022-02-10 18:05:45 +0100789 def _get_infos(self):
790 """
791 Selects the file and returns the total number of entries
792 and entry size
793 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100794
Harald Weltec91085e2022-02-10 18:05:45 +0100795 r = self._scc.select_path(['3f00', '000c'])
796 rec_len = int(r[-1][28:30], 16)
797 tlen = int(r[-1][4:8], 16)
798 rec_cnt = (tlen // rec_len) - 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100799
Harald Weltec91085e2022-02-10 18:05:45 +0100800 if (rec_cnt < 1) or (rec_len != 0x5a):
801 raise RuntimeError('Bad card type')
Sylvain Munaut76504e02010-12-07 00:24:32 +0100802
Harald Weltec91085e2022-02-10 18:05:45 +0100803 return rec_cnt, rec_len
Sylvain Munaut76504e02010-12-07 00:24:32 +0100804
Harald Weltec91085e2022-02-10 18:05:45 +0100805 def program(self, p):
806 # Home PLMN
807 r = self._scc.select_path(['3f00', '7f20', '6f30'])
808 tl = int(r[-1][4:8], 16)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100809
Harald Weltec91085e2022-02-10 18:05:45 +0100810 hplmn = enc_plmn(p['mcc'], p['mnc'])
811 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100812
Harald Weltec91085e2022-02-10 18:05:45 +0100813 # Get total number of entries and entry size
814 rec_cnt, rec_len = self._get_infos()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100815
Harald Weltec91085e2022-02-10 18:05:45 +0100816 # Set first entry
817 entry = (
818 '81' + # 1b Status: Valid & Active
819 rpad(s2h(p['name'][0:14]), 28) + # 14b Entry Name
820 enc_iccid(p['iccid']) + # 10b ICCID
821 enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
822 p['ki'] + # 16b Ki
823 lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
824 )
825 self._scc.update_record('000c', 1, entry)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100826
Harald Weltec91085e2022-02-10 18:05:45 +0100827 def erase(self):
828 # Get total number of entries and entry size
829 rec_cnt, rec_len = self._get_infos()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100830
Harald Weltec91085e2022-02-10 18:05:45 +0100831 # Erase all entries
832 entry = 'ff' * rec_len
833 for i in range(0, rec_cnt):
834 self._scc.update_record('000c', 1+i, entry)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100835
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200836
Philipp Maierbb73e512021-05-05 16:14:00 +0200837class GrcardSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100838 """
839 Greencard (grcard.cn) HZCOS GSM SIM
840 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
841 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
842 """
Harald Welte3156d902011-03-22 21:48:19 +0100843
Harald Weltec91085e2022-02-10 18:05:45 +0100844 name = 'grcardsim'
Harald Welte3156d902011-03-22 21:48:19 +0100845
Harald Weltec91085e2022-02-10 18:05:45 +0100846 @classmethod
847 def autodetect(kls, scc):
848 return None
Harald Welte3156d902011-03-22 21:48:19 +0100849
Harald Weltec91085e2022-02-10 18:05:45 +0100850 def program(self, p):
851 # We don't really know yet what ADM PIN 4 is about
852 #self._scc.verify_chv(4, h2b("4444444444444444"))
Harald Welte3156d902011-03-22 21:48:19 +0100853
Harald Weltec91085e2022-02-10 18:05:45 +0100854 # Authenticate using ADM PIN 5
855 if p['pin_adm']:
856 pin = h2b(p['pin_adm'])
857 else:
858 pin = h2b("4444444444444444")
859 self._scc.verify_chv(5, pin)
Harald Welte3156d902011-03-22 21:48:19 +0100860
Harald Weltec91085e2022-02-10 18:05:45 +0100861 # EF.ICCID
862 r = self._scc.select_path(['3f00', '2fe2'])
863 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100864
Harald Weltec91085e2022-02-10 18:05:45 +0100865 # EF.IMSI
866 r = self._scc.select_path(['3f00', '7f20', '6f07'])
867 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100868
Harald Weltec91085e2022-02-10 18:05:45 +0100869 # EF.ACC
870 if p.get('acc') is not None:
871 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100872
Harald Weltec91085e2022-02-10 18:05:45 +0100873 # EF.SMSP
874 if p.get('smsp'):
875 r = self._scc.select_path(['3f00', '7f10', '6f42'])
876 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100877
Harald Weltec91085e2022-02-10 18:05:45 +0100878 # Set the Ki using proprietary command
879 pdu = '80d4020010' + p['ki']
880 data, sw = self._scc._tp.send_apdu(pdu)
Harald Welte3156d902011-03-22 21:48:19 +0100881
Harald Weltec91085e2022-02-10 18:05:45 +0100882 # EF.HPLMN
883 r = self._scc.select_path(['3f00', '7f20', '6f30'])
884 size = int(r[-1][4:8], 16)
885 hplmn = enc_plmn(p['mcc'], p['mnc'])
886 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
Harald Welte3156d902011-03-22 21:48:19 +0100887
Harald Weltec91085e2022-02-10 18:05:45 +0100888 # EF.SPN (Service Provider Name)
889 r = self._scc.select_path(['3f00', '7f20', '6f30'])
890 size = int(r[-1][4:8], 16)
891 # FIXME
Harald Welte3156d902011-03-22 21:48:19 +0100892
Harald Weltec91085e2022-02-10 18:05:45 +0100893 # FIXME: EF.MSISDN
Harald Welte3156d902011-03-22 21:48:19 +0100894
Sylvain Munaut76504e02010-12-07 00:24:32 +0100895
Harald Weltee10394b2011-12-07 12:34:14 +0100896class SysmoSIMgr1(GrcardSim):
Harald Weltec91085e2022-02-10 18:05:45 +0100897 """
898 sysmocom sysmoSIM-GR1
899 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
900 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
901 """
902 name = 'sysmosim-gr1'
Harald Weltee10394b2011-12-07 12:34:14 +0100903
Harald Weltec91085e2022-02-10 18:05:45 +0100904 @classmethod
905 def autodetect(kls, scc):
906 try:
907 # Look for ATR
908 if scc.get_atr() == toBytes("3B 99 18 00 11 88 22 33 44 55 66 77 60"):
909 return kls(scc)
910 except:
911 return None
912 return None
913
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200914
Harald Welteca673942020-06-03 15:19:40 +0200915class SysmoUSIMgr1(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100916 """
917 sysmocom sysmoUSIM-GR1
918 """
919 name = 'sysmoUSIM-GR1'
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100920
Harald Weltec91085e2022-02-10 18:05:45 +0100921 @classmethod
922 def autodetect(kls, scc):
923 # TODO: Access the ATR
924 return None
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100925
Harald Weltec91085e2022-02-10 18:05:45 +0100926 def program(self, p):
927 # TODO: check if verify_chv could be used or what it needs
928 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
929 # Unlock the card..
930 data, sw = self._scc._tp.send_apdu_checksw(
931 "0020000A083332323133323332")
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100932
Harald Weltec91085e2022-02-10 18:05:45 +0100933 # TODO: move into SimCardCommands
934 par = (p['ki'] + # 16b K
935 p['opc'] + # 32b OPC
936 enc_iccid(p['iccid']) + # 10b ICCID
937 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
938 )
939 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100940
Sylvain Munaut053c8952013-07-02 15:12:32 +0200941
Philipp Maierbb73e512021-05-05 16:14:00 +0200942class SysmoSIMgr2(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100943 """
944 sysmocom sysmoSIM-GR2
945 """
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100946
Harald Weltec91085e2022-02-10 18:05:45 +0100947 name = 'sysmoSIM-GR2'
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100948
Harald Weltec91085e2022-02-10 18:05:45 +0100949 @classmethod
950 def autodetect(kls, scc):
951 try:
952 # Look for ATR
953 if scc.get_atr() == toBytes("3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68"):
954 return kls(scc)
955 except:
956 return None
957 return None
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100958
Harald Weltec91085e2022-02-10 18:05:45 +0100959 def program(self, p):
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100960
Harald Weltec91085e2022-02-10 18:05:45 +0100961 # select MF
962 r = self._scc.select_path(['3f00'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200963
Harald Weltec91085e2022-02-10 18:05:45 +0100964 # authenticate as SUPER ADM using default key
965 self._scc.verify_chv(0x0b, h2b("3838383838383838"))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100966
Harald Weltec91085e2022-02-10 18:05:45 +0100967 # set ADM pin using proprietary command
968 # INS: D4
969 # P1: 3A for PIN, 3B for PUK
970 # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
971 # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
972 if p['pin_adm']:
973 pin = h2b(p['pin_adm'])
974 else:
975 pin = h2b("4444444444444444")
Jan Balkec3ebd332015-01-26 12:22:55 +0100976
Harald Weltec91085e2022-02-10 18:05:45 +0100977 pdu = 'A0D43A0508' + b2h(pin)
978 data, sw = self._scc._tp.send_apdu(pdu)
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200979
Harald Weltec91085e2022-02-10 18:05:45 +0100980 # authenticate as ADM (enough to write file, and can set PINs)
Jan Balkec3ebd332015-01-26 12:22:55 +0100981
Harald Weltec91085e2022-02-10 18:05:45 +0100982 self._scc.verify_chv(0x05, pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100983
Harald Weltec91085e2022-02-10 18:05:45 +0100984 # write EF.ICCID
985 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100986
Harald Weltec91085e2022-02-10 18:05:45 +0100987 # select DF_GSM
988 r = self._scc.select_path(['7f20'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200989
Harald Weltec91085e2022-02-10 18:05:45 +0100990 # write EF.IMSI
991 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100992
Harald Weltec91085e2022-02-10 18:05:45 +0100993 # write EF.ACC
994 if p.get('acc') is not None:
995 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100996
Harald Weltec91085e2022-02-10 18:05:45 +0100997 # get size and write EF.HPLMN
998 r = self._scc.select_path(['6f30'])
999 size = int(r[-1][4:8], 16)
1000 hplmn = enc_plmn(p['mcc'], p['mnc'])
1001 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +01001002
Harald Weltec91085e2022-02-10 18:05:45 +01001003 # set COMP128 version 0 in proprietary file
1004 data, sw = self._scc.update_binary('0001', '001000')
Sylvain Munaut2fc205c2013-12-23 17:22:56 +01001005
Harald Weltec91085e2022-02-10 18:05:45 +01001006 # set Ki in proprietary file
1007 data, sw = self._scc.update_binary('0001', p['ki'], 3)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +01001008
Harald Weltec91085e2022-02-10 18:05:45 +01001009 # select DF_TELECOM
1010 r = self._scc.select_path(['3f00', '7f10'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +02001011
Harald Weltec91085e2022-02-10 18:05:45 +01001012 # write EF.SMSP
1013 if p.get('smsp'):
1014 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +01001015
Sylvain Munaut2fc205c2013-12-23 17:22:56 +01001016
Harald Welteca673942020-06-03 15:19:40 +02001017class SysmoUSIMSJS1(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001018 """
1019 sysmocom sysmoUSIM-SJS1
1020 """
Jan Balke3e840672015-01-26 15:36:27 +01001021
Harald Weltec91085e2022-02-10 18:05:45 +01001022 name = 'sysmoUSIM-SJS1'
Jan Balke3e840672015-01-26 15:36:27 +01001023
Harald Weltec91085e2022-02-10 18:05:45 +01001024 def __init__(self, ssc):
1025 super(SysmoUSIMSJS1, self).__init__(ssc)
1026 self._scc.cla_byte = "00"
1027 self._scc.sel_ctrl = "0004" # request an FCP
Jan Balke3e840672015-01-26 15:36:27 +01001028
Harald Weltec91085e2022-02-10 18:05:45 +01001029 @classmethod
1030 def autodetect(kls, scc):
1031 try:
1032 # Look for ATR
1033 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"):
1034 return kls(scc)
1035 except:
1036 return None
1037 return None
Jan Balke3e840672015-01-26 15:36:27 +01001038
Harald Weltec91085e2022-02-10 18:05:45 +01001039 def verify_adm(self, key):
1040 # authenticate as ADM using default key (written on the card..)
1041 if not key:
1042 raise ValueError(
1043 "Please provide a PIN-ADM as there is no default one")
1044 (res, sw) = self._scc.verify_chv(0x0A, key)
1045 return sw
Harald Weltea6704252021-01-08 20:19:11 +01001046
Harald Weltec91085e2022-02-10 18:05:45 +01001047 def program(self, p):
1048 self.verify_adm(h2b(p['pin_adm']))
Jan Balke3e840672015-01-26 15:36:27 +01001049
Harald Weltec91085e2022-02-10 18:05:45 +01001050 # select MF
1051 r = self._scc.select_path(['3f00'])
Jan Balke3e840672015-01-26 15:36:27 +01001052
Harald Weltec91085e2022-02-10 18:05:45 +01001053 # write EF.ICCID
1054 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Philipp Maiere9604882017-03-21 17:24:31 +01001055
Harald Weltec91085e2022-02-10 18:05:45 +01001056 # select DF_GSM
1057 r = self._scc.select_path(['7f20'])
Jan Balke3e840672015-01-26 15:36:27 +01001058
Harald Weltec91085e2022-02-10 18:05:45 +01001059 # set Ki in proprietary file
1060 data, sw = self._scc.update_binary('00FF', p['ki'])
Jan Balke3e840672015-01-26 15:36:27 +01001061
Harald Weltec91085e2022-02-10 18:05:45 +01001062 # set OPc in proprietary file
1063 if 'opc' in p:
1064 content = "01" + p['opc']
1065 data, sw = self._scc.update_binary('00F7', content)
Jan Balke3e840672015-01-26 15:36:27 +01001066
Harald Weltec91085e2022-02-10 18:05:45 +01001067 # set Service Provider Name
1068 if p.get('name') is not None:
1069 self.update_spn(p['name'], True, True)
Supreeth Herle7947d922019-06-08 07:50:53 +02001070
Harald Weltec91085e2022-02-10 18:05:45 +01001071 if p.get('acc') is not None:
1072 self.update_acc(p['acc'])
Supreeth Herlec8796a32019-12-23 12:23:42 +01001073
Harald Weltec91085e2022-02-10 18:05:45 +01001074 # write EF.IMSI
1075 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Jan Balke3e840672015-01-26 15:36:27 +01001076
Harald Weltec91085e2022-02-10 18:05:45 +01001077 # EF.PLMNsel
1078 if p.get('mcc') and p.get('mnc'):
1079 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1080 if sw != '9000':
1081 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001082
Harald Weltec91085e2022-02-10 18:05:45 +01001083 # EF.PLMNwAcT
1084 if p.get('mcc') and p.get('mnc'):
1085 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1086 if sw != '9000':
1087 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001088
Harald Weltec91085e2022-02-10 18:05:45 +01001089 # EF.OPLMNwAcT
1090 if p.get('mcc') and p.get('mnc'):
1091 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1092 if sw != '9000':
1093 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001094
Harald Weltec91085e2022-02-10 18:05:45 +01001095 # EF.HPLMNwAcT
1096 if p.get('mcc') and p.get('mnc'):
1097 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1098 if sw != '9000':
1099 print("Programming HPLMNwAcT failed with code %s" % sw)
Supreeth Herlef442fb42020-01-21 12:47:32 +01001100
Harald Weltec91085e2022-02-10 18:05:45 +01001101 # EF.AD
1102 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1103 if p.get('mcc') and p.get('mnc'):
1104 mnc = p['mnc']
1105 else:
1106 mnc = None
1107 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1108 if sw != '9000':
1109 print("Programming AD failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001110
Harald Weltec91085e2022-02-10 18:05:45 +01001111 # EF.SMSP
1112 if p.get('smsp'):
1113 r = self._scc.select_path(['3f00', '7f10'])
1114 data, sw = self._scc.update_record(
1115 '6f42', 1, lpad(p['smsp'], 104), force_len=True)
Jan Balke3e840672015-01-26 15:36:27 +01001116
Harald Weltec91085e2022-02-10 18:05:45 +01001117 # EF.MSISDN
1118 # TODO: Alpha Identifier (currently 'ff'O * 20)
1119 # TODO: Capability/Configuration1 Record Identifier
1120 # TODO: Extension1 Record Identifier
1121 if p.get('msisdn') is not None:
1122 msisdn = enc_msisdn(p['msisdn'])
1123 data = 'ff' * 20 + msisdn
Supreeth Herle5a541012019-12-22 08:59:16 +01001124
Harald Weltec91085e2022-02-10 18:05:45 +01001125 r = self._scc.select_path(['3f00', '7f10'])
1126 data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
Supreeth Herle5a541012019-12-22 08:59:16 +01001127
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001128
herlesupreeth4a3580b2020-09-29 10:11:36 +02001129class FairwavesSIM(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001130 """
1131 FairwavesSIM
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001132
Harald Weltec91085e2022-02-10 18:05:45 +01001133 The SIM card is operating according to the standard.
1134 For Ki/OP/OPC programming the following files are additionally open for writing:
1135 3F00/7F20/FF01 – OP/OPC:
1136 byte 1 = 0x01, bytes 2-17: OPC;
1137 byte 1 = 0x00, bytes 2-17: OP;
1138 3F00/7F20/FF02: Ki
1139 """
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001140
Harald Weltec91085e2022-02-10 18:05:45 +01001141 name = 'Fairwaves-SIM'
1142 # Propriatary files
1143 _EF_num = {
1144 'Ki': 'FF02',
1145 'OP/OPC': 'FF01',
1146 }
1147 _EF = {
1148 'Ki': DF['GSM']+[_EF_num['Ki']],
1149 'OP/OPC': DF['GSM']+[_EF_num['OP/OPC']],
1150 }
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001151
Harald Weltec91085e2022-02-10 18:05:45 +01001152 def __init__(self, ssc):
1153 super(FairwavesSIM, self).__init__(ssc)
1154 self._adm_chv_num = 0x11
1155 self._adm2_chv_num = 0x12
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001156
Harald Weltec91085e2022-02-10 18:05:45 +01001157 @classmethod
1158 def autodetect(kls, scc):
1159 try:
1160 # Look for ATR
1161 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"):
1162 return kls(scc)
1163 except:
1164 return None
1165 return None
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001166
Harald Weltec91085e2022-02-10 18:05:45 +01001167 def verify_adm2(self, key):
1168 '''
1169 Authenticate with ADM2 key.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001170
Harald Weltec91085e2022-02-10 18:05:45 +01001171 Fairwaves SIM cards support hierarchical key structure and ADM2 key
1172 is a key which has access to proprietary files (Ki and OP/OPC).
1173 That said, ADM key inherits permissions of ADM2 key and thus we rarely
1174 need ADM2 key per se.
1175 '''
1176 (res, sw) = self._scc.verify_chv(self._adm2_chv_num, key)
1177 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001178
Harald Weltec91085e2022-02-10 18:05:45 +01001179 def read_ki(self):
1180 """
1181 Read Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001182
Harald Weltec91085e2022-02-10 18:05:45 +01001183 Requires ADM1 access level
1184 """
1185 return self._scc.read_binary(self._EF['Ki'])
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001186
Harald Weltec91085e2022-02-10 18:05:45 +01001187 def update_ki(self, ki):
1188 """
1189 Set Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001190
Harald Weltec91085e2022-02-10 18:05:45 +01001191 Requires ADM1 access level
1192 """
1193 data, sw = self._scc.update_binary(self._EF['Ki'], ki)
1194 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001195
Harald Weltec91085e2022-02-10 18:05:45 +01001196 def read_op_opc(self):
1197 """
1198 Read Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001199
Harald Weltec91085e2022-02-10 18:05:45 +01001200 Requires ADM1 access level
1201 """
1202 (ef, sw) = self._scc.read_binary(self._EF['OP/OPC'])
1203 type = 'OP' if ef[0:2] == '00' else 'OPC'
1204 return ((type, ef[2:]), sw)
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001205
Harald Weltec91085e2022-02-10 18:05:45 +01001206 def update_op(self, op):
1207 """
1208 Set OP in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001209
Harald Weltec91085e2022-02-10 18:05:45 +01001210 Requires ADM1 access level
1211 """
1212 content = '00' + op
1213 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
1214 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001215
Harald Weltec91085e2022-02-10 18:05:45 +01001216 def update_opc(self, opc):
1217 """
1218 Set OPC in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001219
Harald Weltec91085e2022-02-10 18:05:45 +01001220 Requires ADM1 access level
1221 """
1222 content = '01' + opc
1223 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
1224 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001225
Harald Weltec91085e2022-02-10 18:05:45 +01001226 def program(self, p):
1227 # For some reason the card programming only works when the card
1228 # is handled as a classic SIM, even though it is an USIM, so we
1229 # reconfigure the class byte and the select control field on
1230 # the fly. When the programming is done the original values are
1231 # restored.
1232 cla_byte_orig = self._scc.cla_byte
1233 sel_ctrl_orig = self._scc.sel_ctrl
1234 self._scc.cla_byte = "a0"
1235 self._scc.sel_ctrl = "0000"
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001236
Harald Weltec91085e2022-02-10 18:05:45 +01001237 try:
1238 self._program(p)
1239 finally:
1240 # restore original cla byte and sel ctrl
1241 self._scc.cla_byte = cla_byte_orig
1242 self._scc.sel_ctrl = sel_ctrl_orig
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001243
Harald Weltec91085e2022-02-10 18:05:45 +01001244 def _program(self, p):
1245 # authenticate as ADM1
1246 if not p['pin_adm']:
1247 raise ValueError(
1248 "Please provide a PIN-ADM as there is no default one")
1249 self.verify_adm(h2b(p['pin_adm']))
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001250
Harald Weltec91085e2022-02-10 18:05:45 +01001251 # TODO: Set operator name
1252 if p.get('smsp') is not None:
1253 sw = self.update_smsp(p['smsp'])
1254 if sw != '9000':
1255 print("Programming SMSP failed with code %s" % sw)
1256 # This SIM doesn't support changing ICCID
1257 if p.get('mcc') is not None and p.get('mnc') is not None:
1258 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1259 if sw != '9000':
1260 print("Programming MCC/MNC failed with code %s" % sw)
1261 if p.get('imsi') is not None:
1262 sw = self.update_imsi(p['imsi'])
1263 if sw != '9000':
1264 print("Programming IMSI failed with code %s" % sw)
1265 if p.get('ki') is not None:
1266 sw = self.update_ki(p['ki'])
1267 if sw != '9000':
1268 print("Programming Ki failed with code %s" % sw)
1269 if p.get('opc') is not None:
1270 sw = self.update_opc(p['opc'])
1271 if sw != '9000':
1272 print("Programming OPC failed with code %s" % sw)
1273 if p.get('acc') is not None:
1274 sw = self.update_acc(p['acc'])
1275 if sw != '9000':
1276 print("Programming ACC failed with code %s" % sw)
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001277
1278
Philipp Maierbb73e512021-05-05 16:14:00 +02001279class OpenCellsSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001280 """
1281 OpenCellsSim
Todd Neal9eeadfc2018-04-25 15:36:29 -05001282
Harald Weltec91085e2022-02-10 18:05:45 +01001283 """
Todd Neal9eeadfc2018-04-25 15:36:29 -05001284
Harald Weltec91085e2022-02-10 18:05:45 +01001285 name = 'OpenCells-SIM'
Todd Neal9eeadfc2018-04-25 15:36:29 -05001286
Harald Weltec91085e2022-02-10 18:05:45 +01001287 def __init__(self, ssc):
1288 super(OpenCellsSim, self).__init__(ssc)
1289 self._adm_chv_num = 0x0A
Todd Neal9eeadfc2018-04-25 15:36:29 -05001290
Harald Weltec91085e2022-02-10 18:05:45 +01001291 @classmethod
1292 def autodetect(kls, scc):
1293 try:
1294 # Look for ATR
1295 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"):
1296 return kls(scc)
1297 except:
1298 return None
1299 return None
Todd Neal9eeadfc2018-04-25 15:36:29 -05001300
Harald Weltec91085e2022-02-10 18:05:45 +01001301 def program(self, p):
1302 if not p['pin_adm']:
1303 raise ValueError(
1304 "Please provide a PIN-ADM as there is no default one")
1305 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001306
Harald Weltec91085e2022-02-10 18:05:45 +01001307 # select MF
1308 r = self._scc.select_path(['3f00'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001309
Harald Weltec91085e2022-02-10 18:05:45 +01001310 # write EF.ICCID
1311 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001312
Harald Weltec91085e2022-02-10 18:05:45 +01001313 r = self._scc.select_path(['7ff0'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001314
Harald Weltec91085e2022-02-10 18:05:45 +01001315 # set Ki in proprietary file
1316 data, sw = self._scc.update_binary('FF02', p['ki'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001317
Harald Weltec91085e2022-02-10 18:05:45 +01001318 # set OPC in proprietary file
1319 data, sw = self._scc.update_binary('FF01', p['opc'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001320
Harald Weltec91085e2022-02-10 18:05:45 +01001321 # select DF_GSM
1322 r = self._scc.select_path(['7f20'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001323
Harald Weltec91085e2022-02-10 18:05:45 +01001324 # write EF.IMSI
1325 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001326
Todd Neal9eeadfc2018-04-25 15:36:29 -05001327
herlesupreeth4a3580b2020-09-29 10:11:36 +02001328class WavemobileSim(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001329 """
1330 WavemobileSim
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001331
Harald Weltec91085e2022-02-10 18:05:45 +01001332 """
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001333
Harald Weltec91085e2022-02-10 18:05:45 +01001334 name = 'Wavemobile-SIM'
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001335
Harald Weltec91085e2022-02-10 18:05:45 +01001336 def __init__(self, ssc):
1337 super(WavemobileSim, self).__init__(ssc)
1338 self._adm_chv_num = 0x0A
1339 self._scc.cla_byte = "00"
1340 self._scc.sel_ctrl = "0004" # request an FCP
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001341
Harald Weltec91085e2022-02-10 18:05:45 +01001342 @classmethod
1343 def autodetect(kls, scc):
1344 try:
1345 # Look for ATR
1346 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"):
1347 return kls(scc)
1348 except:
1349 return None
1350 return None
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001351
Harald Weltec91085e2022-02-10 18:05:45 +01001352 def program(self, p):
1353 if not p['pin_adm']:
1354 raise ValueError(
1355 "Please provide a PIN-ADM as there is no default one")
1356 self.verify_adm(h2b(p['pin_adm']))
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001357
Harald Weltec91085e2022-02-10 18:05:45 +01001358 # EF.ICCID
1359 # TODO: Add programming of the ICCID
1360 if p.get('iccid'):
1361 print(
1362 "Warning: Programming of the ICCID is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001363
Philipp Maierde0cf162023-01-03 13:29:45 +01001364 # KI (Presumably a proprietary file)
Harald Weltec91085e2022-02-10 18:05:45 +01001365 # TODO: Add programming of KI
1366 if p.get('ki'):
1367 print(
1368 "Warning: Programming of the KI is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001369
Philipp Maierde0cf162023-01-03 13:29:45 +01001370 # OPc (Presumably a proprietary file)
Harald Weltec91085e2022-02-10 18:05:45 +01001371 # TODO: Add programming of OPc
1372 if p.get('opc'):
1373 print(
1374 "Warning: Programming of the OPc is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001375
Harald Weltec91085e2022-02-10 18:05:45 +01001376 # EF.SMSP
1377 if p.get('smsp'):
1378 sw = self.update_smsp(p['smsp'])
1379 if sw != '9000':
1380 print("Programming SMSP failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001381
Harald Weltec91085e2022-02-10 18:05:45 +01001382 # EF.IMSI
1383 if p.get('imsi'):
1384 sw = self.update_imsi(p['imsi'])
1385 if sw != '9000':
1386 print("Programming IMSI failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001387
Harald Weltec91085e2022-02-10 18:05:45 +01001388 # EF.ACC
1389 if p.get('acc'):
1390 sw = self.update_acc(p['acc'])
1391 if sw != '9000':
1392 print("Programming ACC failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001393
Harald Weltec91085e2022-02-10 18:05:45 +01001394 # EF.PLMNsel
1395 if p.get('mcc') and p.get('mnc'):
1396 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1397 if sw != '9000':
1398 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001399
Harald Weltec91085e2022-02-10 18:05:45 +01001400 # EF.PLMNwAcT
1401 if p.get('mcc') and p.get('mnc'):
1402 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1403 if sw != '9000':
1404 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001405
Harald Weltec91085e2022-02-10 18:05:45 +01001406 # EF.OPLMNwAcT
1407 if p.get('mcc') and p.get('mnc'):
1408 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1409 if sw != '9000':
1410 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001411
Harald Weltec91085e2022-02-10 18:05:45 +01001412 # EF.AD
1413 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1414 if p.get('mcc') and p.get('mnc'):
1415 mnc = p['mnc']
1416 else:
1417 mnc = None
1418 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1419 if sw != '9000':
1420 print("Programming AD failed with code %s" % sw)
Philipp Maier6e507a72019-04-01 16:33:48 +02001421
Harald Weltec91085e2022-02-10 18:05:45 +01001422 return None
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001423
Todd Neal9eeadfc2018-04-25 15:36:29 -05001424
herlesupreethb0c7d122020-12-23 09:25:46 +01001425class SysmoISIMSJA2(UsimCard, IsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001426 """
1427 sysmocom sysmoISIM-SJA2
1428 """
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001429
Harald Weltec91085e2022-02-10 18:05:45 +01001430 name = 'sysmoISIM-SJA2'
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001431
Harald Weltec91085e2022-02-10 18:05:45 +01001432 def __init__(self, ssc):
1433 super(SysmoISIMSJA2, self).__init__(ssc)
1434 self._scc.cla_byte = "00"
1435 self._scc.sel_ctrl = "0004" # request an FCP
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001436
Harald Weltec91085e2022-02-10 18:05:45 +01001437 @classmethod
1438 def autodetect(kls, scc):
1439 try:
1440 # Try card model #1
1441 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9"
1442 if scc.get_atr() == toBytes(atr):
1443 return kls(scc)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001444
Harald Weltec91085e2022-02-10 18:05:45 +01001445 # Try card model #2
1446 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2"
1447 if scc.get_atr() == toBytes(atr):
1448 return kls(scc)
Philipp Maierb3e11ea2020-03-11 12:32:44 +01001449
Harald Weltec91085e2022-02-10 18:05:45 +01001450 # Try card model #3
1451 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"
1452 if scc.get_atr() == toBytes(atr):
1453 return kls(scc)
1454 except:
1455 return None
1456 return None
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001457
Harald Weltec91085e2022-02-10 18:05:45 +01001458 def verify_adm(self, key):
1459 # authenticate as ADM using default key (written on the card..)
1460 if not key:
1461 raise ValueError(
1462 "Please provide a PIN-ADM as there is no default one")
1463 (res, sw) = self._scc.verify_chv(0x0A, key)
1464 return sw
Harald Weltea6704252021-01-08 20:19:11 +01001465
Harald Weltec91085e2022-02-10 18:05:45 +01001466 def program(self, p):
1467 self.verify_adm(h2b(p['pin_adm']))
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001468
Philipp Maier84902402023-02-10 18:23:36 +01001469 # Populate AIDs
1470 self.read_aids()
1471
Harald Weltec91085e2022-02-10 18:05:45 +01001472 # This type of card does not allow to reprogram the ICCID.
1473 # Reprogramming the ICCID would mess up the card os software
1474 # license management, so the ICCID must be kept at its factory
1475 # setting!
1476 if p.get('iccid'):
1477 print(
1478 "Warning: Programming of the ICCID is not implemented for this type of card.")
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001479
Harald Weltec91085e2022-02-10 18:05:45 +01001480 # select DF_GSM
1481 self._scc.select_path(['7f20'])
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001482
Harald Weltec91085e2022-02-10 18:05:45 +01001483 # set Service Provider Name
1484 if p.get('name') is not None:
1485 self.update_spn(p['name'], True, True)
Robert Falkenberg54595362021-04-06 12:04:34 +02001486
Harald Weltec91085e2022-02-10 18:05:45 +01001487 # write EF.IMSI
1488 if p.get('imsi'):
1489 self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001490
Harald Weltec91085e2022-02-10 18:05:45 +01001491 # EF.PLMNsel
1492 if p.get('mcc') and p.get('mnc'):
1493 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1494 if sw != '9000':
1495 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001496
Harald Weltec91085e2022-02-10 18:05:45 +01001497 # EF.PLMNwAcT
1498 if p.get('mcc') and p.get('mnc'):
1499 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1500 if sw != '9000':
1501 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001502
Harald Weltec91085e2022-02-10 18:05:45 +01001503 # EF.OPLMNwAcT
1504 if p.get('mcc') and p.get('mnc'):
1505 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1506 if sw != '9000':
1507 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001508
Harald Weltec91085e2022-02-10 18:05:45 +01001509 # EF.HPLMNwAcT
1510 if p.get('mcc') and p.get('mnc'):
1511 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1512 if sw != '9000':
1513 print("Programming HPLMNwAcT failed with code %s" % sw)
Harald Welte32f0d412020-05-05 17:35:57 +02001514
Harald Weltec91085e2022-02-10 18:05:45 +01001515 # EF.AD
1516 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1517 if p.get('mcc') and p.get('mnc'):
1518 mnc = p['mnc']
1519 else:
1520 mnc = None
1521 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1522 if sw != '9000':
1523 print("Programming AD failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001524
Harald Weltec91085e2022-02-10 18:05:45 +01001525 # EF.SMSP
1526 if p.get('smsp'):
1527 r = self._scc.select_path(['3f00', '7f10'])
1528 data, sw = self._scc.update_record(
1529 '6f42', 1, lpad(p['smsp'], 104), force_len=True)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001530
Harald Weltec91085e2022-02-10 18:05:45 +01001531 # EF.MSISDN
1532 # TODO: Alpha Identifier (currently 'ff'O * 20)
1533 # TODO: Capability/Configuration1 Record Identifier
1534 # TODO: Extension1 Record Identifier
1535 if p.get('msisdn') is not None:
1536 msisdn = enc_msisdn(p['msisdn'])
1537 content = 'ff' * 20 + msisdn
Supreeth Herlec6019232020-03-26 10:00:45 +01001538
Harald Weltec91085e2022-02-10 18:05:45 +01001539 r = self._scc.select_path(['3f00', '7f10'])
1540 data, sw = self._scc.update_record(
1541 '6F40', 1, content, force_len=True)
Supreeth Herlec6019232020-03-26 10:00:45 +01001542
Harald Weltec91085e2022-02-10 18:05:45 +01001543 # EF.ACC
1544 if p.get('acc'):
1545 sw = self.update_acc(p['acc'])
1546 if sw != '9000':
1547 print("Programming ACC failed with code %s" % sw)
Supreeth Herlea97944b2020-03-26 10:03:25 +01001548
Harald Weltec91085e2022-02-10 18:05:45 +01001549 # update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
1550 # hard linked to EF-USIM_AUTH_KEY)
1551 self._scc.select_path(['3f00'])
1552 self._scc.select_path(['a515'])
1553 if p.get('ki'):
1554 self._scc.update_binary('6f20', p['ki'], 1)
1555 if p.get('opc'):
1556 self._scc.update_binary('6f20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001557
Harald Weltec91085e2022-02-10 18:05:45 +01001558 # update EF-USIM_AUTH_KEY in ADF.ISIM
Philipp Maier84902402023-02-10 18:23:36 +01001559 if self.adf_present("isim"):
1560 self.select_adf_by_aid(adf="isim")
1561
Harald Weltec91085e2022-02-10 18:05:45 +01001562 if p.get('ki'):
1563 self._scc.update_binary('af20', p['ki'], 1)
1564 if p.get('opc'):
1565 self._scc.update_binary('af20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001566
Harald Weltec91085e2022-02-10 18:05:45 +01001567 # update EF.P-CSCF in ADF.ISIM
1568 if self.file_exists(EF_ISIM_ADF_map['PCSCF']):
1569 if p.get('pcscf'):
1570 sw = self.update_pcscf(p['pcscf'])
1571 else:
1572 sw = self.update_pcscf("")
1573 if sw != '9000':
1574 print("Programming P-CSCF failed with code %s" % sw)
Supreeth Herlecf727f22020-03-24 17:32:21 +01001575
Harald Weltec91085e2022-02-10 18:05:45 +01001576 # update EF.DOMAIN in ADF.ISIM
1577 if self.file_exists(EF_ISIM_ADF_map['DOMAIN']):
1578 if p.get('ims_hdomain'):
1579 sw = self.update_domain(domain=p['ims_hdomain'])
1580 else:
1581 sw = self.update_domain()
Supreeth Herlecf727f22020-03-24 17:32:21 +01001582
Harald Weltec91085e2022-02-10 18:05:45 +01001583 if sw != '9000':
1584 print(
1585 "Programming Home Network Domain Name failed with code %s" % sw)
Supreeth Herle79f43dd2020-03-25 11:43:19 +01001586
Harald Weltec91085e2022-02-10 18:05:45 +01001587 # update EF.IMPI in ADF.ISIM
1588 # TODO: Validate IMPI input
1589 if self.file_exists(EF_ISIM_ADF_map['IMPI']):
1590 if p.get('impi'):
1591 sw = self.update_impi(p['impi'])
1592 else:
1593 sw = self.update_impi()
1594 if sw != '9000':
1595 print("Programming IMPI failed with code %s" % sw)
Supreeth Herle79f43dd2020-03-25 11:43:19 +01001596
Harald Weltec91085e2022-02-10 18:05:45 +01001597 # update EF.IMPU in ADF.ISIM
1598 # TODO: Validate IMPU input
1599 # Support multiple IMPU if there is enough space
1600 if self.file_exists(EF_ISIM_ADF_map['IMPU']):
1601 if p.get('impu'):
1602 sw = self.update_impu(p['impu'])
1603 else:
1604 sw = self.update_impu()
1605 if sw != '9000':
1606 print("Programming IMPU failed with code %s" % sw)
Supreeth Herlea5bd9682020-03-26 09:16:14 +01001607
Philipp Maier84902402023-02-10 18:23:36 +01001608 if self.adf_present("usim"):
1609 self.select_adf_by_aid(adf="usim")
1610
Philipp Maier284ac102023-01-17 14:26:56 +01001611 # EF.AD in ADF.USIM
1612 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1613 if p.get('mcc') and p.get('mnc'):
1614 mnc = p['mnc']
1615 else:
1616 mnc = None
1617 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'),
1618 path=EF_USIM_ADF_map['AD'])
1619 if sw != '9000':
1620 print("Programming AD failed with code %s" % sw)
1621
Harald Weltec91085e2022-02-10 18:05:45 +01001622 # update EF-USIM_AUTH_KEY in ADF.USIM
1623 if p.get('ki'):
1624 self._scc.update_binary('af20', p['ki'], 1)
1625 if p.get('opc'):
1626 self._scc.update_binary('af20', p['opc'], 17)
Supreeth Herlebe7007e2020-03-26 09:27:45 +01001627
Harald Weltec91085e2022-02-10 18:05:45 +01001628 # update EF.EHPLMN in ADF.USIM
1629 if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
1630 if p.get('mcc') and p.get('mnc'):
1631 sw = self.update_ehplmn(p['mcc'], p['mnc'])
1632 if sw != '9000':
1633 print("Programming EHPLMN failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001634
Harald Weltec91085e2022-02-10 18:05:45 +01001635 # update EF.ePDGId in ADF.USIM
1636 if self.file_exists(EF_USIM_ADF_map['ePDGId']):
1637 if p.get('epdgid'):
1638 sw = self.update_epdgid(p['epdgid'])
1639 else:
1640 sw = self.update_epdgid("")
1641 if sw != '9000':
1642 print("Programming ePDGId failed with code %s" % sw)
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001643
Harald Weltec91085e2022-02-10 18:05:45 +01001644 # update EF.ePDGSelection in ADF.USIM
1645 if self.file_exists(EF_USIM_ADF_map['ePDGSelection']):
1646 if p.get('epdgSelection'):
1647 epdg_plmn = p['epdgSelection']
1648 sw = self.update_ePDGSelection(
1649 epdg_plmn[:3], epdg_plmn[3:])
1650 else:
1651 sw = self.update_ePDGSelection("", "")
1652 if sw != '9000':
1653 print("Programming ePDGSelection failed with code %s" % sw)
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001654
Harald Weltec91085e2022-02-10 18:05:45 +01001655 # After successfully programming EF.ePDGId and EF.ePDGSelection,
1656 # Set service 106 and 107 as available in EF.UST
1657 # Disable service 95, 99, 115 if ISIM application is present
1658 if self.file_exists(EF_USIM_ADF_map['UST']):
1659 if p.get('epdgSelection') and p.get('epdgid'):
1660 sw = self.update_ust(106, 1)
1661 if sw != '9000':
1662 print("Programming UST failed with code %s" % sw)
1663 sw = self.update_ust(107, 1)
1664 if sw != '9000':
1665 print("Programming UST failed with code %s" % sw)
Supreeth Herlef964df42020-03-24 13:15:37 +01001666
Harald Weltec91085e2022-02-10 18:05:45 +01001667 sw = self.update_ust(95, 0)
1668 if sw != '9000':
1669 print("Programming UST failed with code %s" % sw)
1670 sw = self.update_ust(99, 0)
1671 if sw != '9000':
1672 print("Programming UST failed with code %s" % sw)
1673 sw = self.update_ust(115, 0)
1674 if sw != '9000':
1675 print("Programming UST failed with code %s" % sw)
Supreeth Herlef964df42020-03-24 13:15:37 +01001676
Harald Weltec91085e2022-02-10 18:05:45 +01001677 return
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001678
Harald Welte0489ae62023-05-24 10:28:34 +02001679class SysmoISIMSJA5(SysmoISIMSJA2):
1680 """
1681 sysmocom sysmoISIM-SJA5
1682 """
1683
1684 name = 'sysmoISIM-SJA5'
1685
1686 @classmethod
1687 def autodetect(kls, scc):
1688 try:
1689 # Try card model #1 (9FJ)
1690 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 51 CC"
1691 if scc.get_atr() == toBytes(atr):
1692 return kls(scc)
1693 # Try card model #2 (SLM17)
1694 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 65 F8"
1695 if scc.get_atr() == toBytes(atr):
1696 return kls(scc)
1697 # Try card model #3 (9FV)
1698 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 59 C4"
1699 if scc.get_atr() == toBytes(atr):
1700 return kls(scc)
1701 except:
1702 return None
1703 return None
1704
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001705
Matan Perelmanc296cb52023-05-11 12:49:17 +03001706class GialerSim(UsimCard):
1707 """
1708 Gialer sim cards (www.gialer.com).
1709 """
1710 name = 'gialersim'
1711
1712 def __init__(self, ssc):
1713 super().__init__(ssc)
1714 self._program_handlers = {
1715 'iccid': self.update_iccid,
1716 'imsi': self.update_imsi,
1717 'acc': self.update_acc,
1718 'smsp': self.update_smsp,
1719 'ki': self.update_ki,
1720 'opc': self.update_opc,
Matan Perelman777ee9e2023-05-14 08:58:50 +03001721 'fplmn': self.update_fplmn,
Matan Perelmanc296cb52023-05-11 12:49:17 +03001722 }
1723
1724 @classmethod
1725 def autodetect(cls, scc):
1726 try:
1727 # Look for ATR
1728 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'):
1729 return cls(scc)
1730 except:
1731 return None
1732 return None
1733
1734 def program(self, p):
Matan Perelman777ee9e2023-05-14 08:58:50 +03001735 self.set_apdu_parameter('00', '0004')
Matan Perelmanc296cb52023-05-11 12:49:17 +03001736 # Authenticate
1737 self._scc.verify_chv(0xc, h2b('3834373936313533'))
1738 for handler in self._program_handlers:
1739 if p.get(handler) is not None:
1740 self._program_handlers[handler](p[handler])
1741
1742 mcc = p.get('mcc')
1743 mnc = p.get('mnc')
1744 has_plmn = mcc is not None and mnc is not None
1745 # EF.HPLMN
1746 if has_plmn:
1747 self.update_hplmn_act(mcc, mnc)
1748
1749 # EF.AD
1750 if has_plmn or (p.get('opmode') is not None):
1751 self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1752
1753 def update_smsp(self, smsp):
1754 data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 80))
1755 return sw
1756
1757 def update_ki(self, ki):
1758 self._scc.select_path(['3f00', '0001'])
1759 self._scc.update_binary('0001', ki)
1760
1761 def update_opc(self, opc):
1762 self._scc.select_path(['3f00', '6002'])
1763 # No idea why the '01' is required
1764 self._scc.update_binary('6002', '01' + opc)
1765
1766
Todd Neal9eeadfc2018-04-25 15:36:29 -05001767# In order for autodetection ...
Harald Weltec91085e2022-02-10 18:05:45 +01001768_cards_classes = [FakeMagicSim, SuperSim, MagicSim, GrcardSim,
1769 SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
Harald Welte0489ae62023-05-24 10:28:34 +02001770 FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2,
Matan Perelmanc296cb52023-05-11 12:49:17 +03001771 SysmoISIMSJA5, GialerSim]
Harald Weltec91085e2022-02-10 18:05:45 +01001772
Alexander Chemeris8ad124a2018-01-10 14:17:55 +09001773
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001774def card_detect(ctype, scc):
Harald Weltec91085e2022-02-10 18:05:45 +01001775 # Detect type if needed
1776 card = None
1777 ctypes = dict([(kls.name, kls) for kls in _cards_classes])
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001778
Harald Weltec91085e2022-02-10 18:05:45 +01001779 if ctype == "auto":
1780 for kls in _cards_classes:
1781 card = kls.autodetect(scc)
1782 if card:
1783 print("Autodetected card type: %s" % card.name)
1784 card.reset()
1785 break
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001786
Harald Weltec91085e2022-02-10 18:05:45 +01001787 if card is None:
1788 print("Autodetection failed")
1789 return None
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001790
Harald Weltec91085e2022-02-10 18:05:45 +01001791 elif ctype in ctypes:
1792 card = ctypes[ctype](scc)
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001793
Harald Weltec91085e2022-02-10 18:05:45 +01001794 else:
1795 raise ValueError("Unknown card type: %s" % ctype)
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001796
Harald Weltec91085e2022-02-10 18:05:45 +01001797 return card