blob: c3766e96b899a6f7d0687874ecc1d25ff50b055d [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
Philipp Maierbb73e512021-05-05 16:14:00 +020055class SimCard(object):
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()
66 if rc is 1:
67 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
Harald Weltec91085e2022-02-10 18:05:45 +010094 def read_imsi(self):
95 (res, sw) = self._scc.read_binary(EF['IMSI'])
96 if sw == '9000':
97 return (dec_imsi(res), sw)
98 else:
99 return (None, sw)
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300100
Harald Weltec91085e2022-02-10 18:05:45 +0100101 def update_imsi(self, imsi):
102 data, sw = self._scc.update_binary(EF['IMSI'], enc_imsi(imsi))
103 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300104
Harald Weltec91085e2022-02-10 18:05:45 +0100105 def update_acc(self, acc):
106 data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4, c='0'))
107 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300108
Harald Weltec91085e2022-02-10 18:05:45 +0100109 def read_hplmn_act(self):
110 (res, sw) = self._scc.read_binary(EF['HPLMNAcT'])
111 if sw == '9000':
112 return (format_xplmn_w_act(res), sw)
113 else:
114 return (None, sw)
Supreeth Herlea850a472020-03-19 12:44:11 +0100115
Harald Weltec91085e2022-02-10 18:05:45 +0100116 def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
117 """
118 Update Home PLMN with access technology bit-field
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300119
Harald Weltec91085e2022-02-10 18:05:45 +0100120 See Section "10.3.37 EFHPLMNwAcT (HPLMN Selector with Access Technology)"
121 in ETSI TS 151 011 for the details of the access_tech field coding.
122 Some common values:
123 access_tech = '0080' # Only GSM is selected
124 access_tech = 'FFFF' # All technologies selected, even Reserved for Future Use ones
125 """
126 # get size and write EF.HPLMNwAcT
127 data = self._scc.read_binary(EF['HPLMNwAcT'], length=None, offset=0)
128 size = len(data[0]) // 2
129 hplmn = enc_plmn(mcc, mnc)
130 content = hplmn + access_tech
131 data, sw = self._scc.update_binary(
132 EF['HPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
133 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300134
Harald Weltec91085e2022-02-10 18:05:45 +0100135 def read_oplmn_act(self):
136 (res, sw) = self._scc.read_binary(EF['OPLMNwAcT'])
137 if sw == '9000':
138 return (format_xplmn_w_act(res), sw)
139 else:
140 return (None, sw)
Supreeth Herle1757b262020-03-19 12:43:11 +0100141
Harald Weltec91085e2022-02-10 18:05:45 +0100142 def update_oplmn_act(self, mcc, mnc, access_tech='FFFF'):
143 """get size and write EF.OPLMNwAcT, See note in update_hplmn_act()"""
144 data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
145 size = len(data[0]) // 2
146 hplmn = enc_plmn(mcc, mnc)
147 content = hplmn + access_tech
148 data, sw = self._scc.update_binary(
149 EF['OPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
150 return sw
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200151
Harald Weltec91085e2022-02-10 18:05:45 +0100152 def read_plmn_act(self):
153 (res, sw) = self._scc.read_binary(EF['PLMNwAcT'])
154 if sw == '9000':
155 return (format_xplmn_w_act(res), sw)
156 else:
157 return (None, sw)
Supreeth Herle14084402020-03-19 12:42:10 +0100158
Harald Weltec91085e2022-02-10 18:05:45 +0100159 def update_plmn_act(self, mcc, mnc, access_tech='FFFF'):
160 """get size and write EF.PLMNwAcT, See note in update_hplmn_act()"""
161 data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
162 size = len(data[0]) // 2
163 hplmn = enc_plmn(mcc, mnc)
164 content = hplmn + access_tech
165 data, sw = self._scc.update_binary(
166 EF['PLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
167 return sw
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200168
Harald Weltec91085e2022-02-10 18:05:45 +0100169 def update_plmnsel(self, mcc, mnc):
170 data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
171 size = len(data[0]) // 2
172 hplmn = enc_plmn(mcc, mnc)
173 data, sw = self._scc.update_binary(
174 EF['PLMNsel'], hplmn + 'ff' * (size-3))
175 return sw
Philipp Maier5bf42602018-07-11 23:23:40 +0200176
Harald Weltec91085e2022-02-10 18:05:45 +0100177 def update_smsp(self, smsp):
178 data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 84))
179 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300180
Harald Weltec91085e2022-02-10 18:05:45 +0100181 def update_ad(self, mnc=None, opmode=None, ofm=None):
182 """
183 Update Administrative Data (AD)
Philipp Maieree908ae2019-03-21 16:21:12 +0100184
Harald Weltec91085e2022-02-10 18:05:45 +0100185 See Sec. "4.2.18 EF_AD (Administrative Data)"
186 in 3GPP TS 31.102 for the details of the EF_AD contents.
Philipp Maier7f9f64a2020-05-11 21:28:52 +0200187
Harald Weltec91085e2022-02-10 18:05:45 +0100188 Set any parameter to None to keep old value(s) on card.
Philipp Maier7f9f64a2020-05-11 21:28:52 +0200189
Harald Weltec91085e2022-02-10 18:05:45 +0100190 Parameters:
191 mnc (str): MNC of IMSI
192 opmode (Hex-str, 1 Byte): MS Operation Mode
193 ofm (Hex-str, 1 Byte): Operational Feature Monitor (OFM) aka Ciphering Indicator
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100194
Harald Weltec91085e2022-02-10 18:05:45 +0100195 Returns:
196 str: Return code of write operation
197 """
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100198
Harald Weltec91085e2022-02-10 18:05:45 +0100199 ad = EF_AD()
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100200
Harald Weltec91085e2022-02-10 18:05:45 +0100201 # read from card
202 raw_hex_data, sw = self._scc.read_binary(
203 EF['AD'], length=None, offset=0)
204 abstract_data = ad.decode_hex(raw_hex_data)
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100205
Harald Weltec91085e2022-02-10 18:05:45 +0100206 # perform updates
207 if mnc and abstract_data['extensions']:
208 mnclen = len(str(mnc))
209 if mnclen == 1:
210 mnclen = 2
211 if mnclen > 3:
212 raise RuntimeError('invalid length of mnc "{}"'.format(mnc))
213 abstract_data['extensions']['mnc_len'] = mnclen
214 if opmode:
215 opmode_num = int(opmode, 16)
216 if opmode_num in [int(v) for v in EF_AD.OP_MODE]:
217 abstract_data['ms_operation_mode'] = opmode_num
218 else:
219 raise RuntimeError('invalid opmode "{}"'.format(opmode))
220 if ofm:
221 abstract_data['ofm'] = bool(int(ofm, 16))
Robert Falkenbergd0505bd2021-02-24 14:06:18 +0100222
Harald Weltec91085e2022-02-10 18:05:45 +0100223 # write to card
224 raw_hex_data = ad.encode_hex(abstract_data)
225 data, sw = self._scc.update_binary(EF['AD'], raw_hex_data)
226 return sw
Philipp Maieree908ae2019-03-21 16:21:12 +0100227
Harald Weltec91085e2022-02-10 18:05:45 +0100228 def read_spn(self):
229 (content, sw) = self._scc.read_binary(EF['SPN'])
230 if sw == '9000':
231 abstract_data = EF_SPN().decode_hex(content)
232 show_in_hplmn = abstract_data['show_in_hplmn']
233 hide_in_oplmn = abstract_data['hide_in_oplmn']
234 name = abstract_data['spn']
235 return ((name, show_in_hplmn, hide_in_oplmn), sw)
236 else:
237 return (None, sw)
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300238
Harald Weltec91085e2022-02-10 18:05:45 +0100239 def update_spn(self, name="", show_in_hplmn=False, hide_in_oplmn=False):
240 abstract_data = {
241 'hide_in_oplmn': hide_in_oplmn,
242 'show_in_hplmn': show_in_hplmn,
243 'spn': name,
244 }
245 content = EF_SPN().encode_hex(abstract_data)
246 data, sw = self._scc.update_binary(EF['SPN'], content)
247 return sw
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300248
Harald Weltec91085e2022-02-10 18:05:45 +0100249 def read_binary(self, ef, length=None, offset=0):
250 ef_path = ef in EF and EF[ef] or ef
251 return self._scc.read_binary(ef_path, length, offset)
Supreeth Herled21349a2020-04-01 08:37:47 +0200252
Harald Weltec91085e2022-02-10 18:05:45 +0100253 def read_record(self, ef, rec_no):
254 ef_path = ef in EF and EF[ef] or ef
255 return self._scc.read_record(ef_path, rec_no)
Supreeth Herlead10d662020-04-01 08:43:08 +0200256
Harald Weltec91085e2022-02-10 18:05:45 +0100257 def read_gid1(self):
258 (res, sw) = self._scc.read_binary(EF['GID1'])
259 if sw == '9000':
260 return (res, sw)
261 else:
262 return (None, sw)
Supreeth Herle98a69272020-03-18 12:14:48 +0100263
Harald Weltec91085e2022-02-10 18:05:45 +0100264 def read_msisdn(self):
265 (res, sw) = self._scc.read_record(EF['MSISDN'], 1)
266 if sw == '9000':
267 return (dec_msisdn(res), sw)
268 else:
269 return (None, sw)
Supreeth Herle6d66af62020-03-19 12:49:16 +0100270
Harald Weltec91085e2022-02-10 18:05:45 +0100271 def read_aids(self):
272 """Fetch all the AIDs present on UICC"""
273 self._aids = []
274 try:
275 # Find out how many records the EF.DIR has
276 # and store all the AIDs in the UICC
277 rec_cnt = self._scc.record_count(EF['DIR'])
278 for i in range(0, rec_cnt):
279 rec = self._scc.read_record(EF['DIR'], i + 1)
280 if (rec[0][0:2], rec[0][4:6]) == ('61', '4f') and len(rec[0]) > 12 \
281 and rec[0][8:8 + int(rec[0][6:8], 16) * 2] not in self._aids:
282 self._aids.append(rec[0][8:8 + int(rec[0][6:8], 16) * 2])
283 except Exception as e:
284 print("Can't read AIDs from SIM -- %s" % (str(e),))
285 self._aids = []
286 return self._aids
Supreeth Herlee4e98312020-03-18 11:33:14 +0100287
Harald Weltec91085e2022-02-10 18:05:45 +0100288 @staticmethod
289 def _get_aid(adf="usim") -> str:
290 aid_map = {}
291 # First (known) halves of the U/ISIM AID
292 aid_map["usim"] = "a0000000871002"
293 aid_map["isim"] = "a0000000871004"
294 adf = adf.lower()
295 if adf in aid_map:
296 return aid_map[adf]
297 return None
Philipp Maier46c61542021-11-16 16:36:50 +0100298
Harald Weltec91085e2022-02-10 18:05:45 +0100299 def _complete_aid(self, aid) -> str:
300 """find the complete version of an ADF.U/ISIM AID"""
301 # Find full AID by partial AID:
302 if is_hex(aid):
303 for aid_known in self._aids:
304 if len(aid_known) >= len(aid) and aid == aid_known[0:len(aid)]:
305 return aid_known
306 return None
Philipp Maier46c61542021-11-16 16:36:50 +0100307
Harald Weltec91085e2022-02-10 18:05:45 +0100308 def select_adf_by_aid(self, adf="usim"):
309 """Select ADF.U/ISIM in the Card using its full AID"""
310 if is_hex(adf):
311 aid = adf
312 else:
313 aid = self._get_aid(adf)
314 if aid:
315 aid_full = self._complete_aid(aid)
316 if aid_full:
317 return self._scc.select_adf(aid_full)
318 else:
319 # If we cannot get the full AID, try with short AID
320 return self._scc.select_adf(aid)
321 return (None, None)
Supreeth Herlef9f3e5e2020-03-22 08:04:59 +0100322
Harald Weltec91085e2022-02-10 18:05:45 +0100323 def erase_binary(self, ef):
324 """Erase the contents of a file"""
325 len = self._scc.binary_size(ef)
326 self._scc.update_binary(ef, "ff" * len, offset=0, verify=True)
Philipp Maier5c2cc662020-05-12 16:27:12 +0200327
Harald Weltec91085e2022-02-10 18:05:45 +0100328 def erase_record(self, ef, rec_no):
329 """Erase the contents of a single record"""
330 len = self._scc.record_size(ef)
331 self._scc.update_record(ef, rec_no, "ff" * len,
332 force_len=False, verify=True)
Philipp Maier5c2cc662020-05-12 16:27:12 +0200333
Harald Weltec91085e2022-02-10 18:05:45 +0100334 def set_apdu_parameter(self, cla, sel_ctrl):
335 """Set apdu parameters (class byte and selection control bytes)"""
336 self._scc.cla_byte = cla
337 self._scc.sel_ctrl = sel_ctrl
Philipp Maier30b225f2021-10-29 16:41:46 +0200338
Harald Weltec91085e2022-02-10 18:05:45 +0100339 def get_apdu_parameter(self):
340 """Get apdu parameters (class byte and selection control bytes)"""
341 return (self._scc.cla_byte, self._scc.sel_ctrl)
342
Philipp Maier30b225f2021-10-29 16:41:46 +0200343
Philipp Maierbb73e512021-05-05 16:14:00 +0200344class UsimCard(SimCard):
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200345
Harald Weltec91085e2022-02-10 18:05:45 +0100346 name = 'USIM'
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200347
Harald Weltec91085e2022-02-10 18:05:45 +0100348 def __init__(self, ssc):
349 super(UsimCard, self).__init__(ssc)
Harald Welteca673942020-06-03 15:19:40 +0200350
Harald Weltec91085e2022-02-10 18:05:45 +0100351 def read_ehplmn(self):
352 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'])
353 if sw == '9000':
354 return (format_xplmn(res), sw)
355 else:
356 return (None, sw)
Harald Welteca673942020-06-03 15:19:40 +0200357
Harald Weltec91085e2022-02-10 18:05:45 +0100358 def update_ehplmn(self, mcc, mnc):
359 data = self._scc.read_binary(
360 EF_USIM_ADF_map['EHPLMN'], length=None, offset=0)
361 size = len(data[0]) // 2
362 ehplmn = enc_plmn(mcc, mnc)
363 data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], ehplmn)
364 return sw
Harald Welteca673942020-06-03 15:19:40 +0200365
Harald Weltec91085e2022-02-10 18:05:45 +0100366 def read_epdgid(self):
367 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
368 if sw == '9000':
369 try:
370 addr, addr_type = dec_addr_tlv(res)
371 except:
372 addr = None
373 addr_type = None
374 return (format_addr(addr, addr_type), sw)
375 else:
376 return (None, sw)
herlesupreethf8232db2020-09-29 10:03:06 +0200377
Harald Weltec91085e2022-02-10 18:05:45 +0100378 def update_epdgid(self, epdgid):
379 size = self._scc.binary_size(EF_USIM_ADF_map['ePDGId']) * 2
380 if len(epdgid) > 0:
381 addr_type = get_addr_type(epdgid)
382 if addr_type == None:
383 raise ValueError(
384 "Unknown ePDG Id address type or invalid address provided")
385 epdgid_tlv = rpad(enc_addr_tlv(epdgid, ('%02x' % addr_type)), size)
386 else:
387 epdgid_tlv = rpad('ff', size)
388 data, sw = self._scc.update_binary(
389 EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
390 return sw
Harald Welteca673942020-06-03 15:19:40 +0200391
Harald Weltec91085e2022-02-10 18:05:45 +0100392 def read_ePDGSelection(self):
393 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGSelection'])
394 if sw == '9000':
395 return (format_ePDGSelection(res), sw)
396 else:
397 return (None, sw)
Supreeth Herle99d55552020-03-24 13:03:43 +0100398
Harald Weltec91085e2022-02-10 18:05:45 +0100399 def update_ePDGSelection(self, mcc, mnc):
400 (res, sw) = self._scc.read_binary(
401 EF_USIM_ADF_map['ePDGSelection'], length=None, offset=0)
402 if sw == '9000' and (len(mcc) == 0 or len(mnc) == 0):
403 # Reset contents
404 # 80 - Tag value
405 (res, sw) = self._scc.update_binary(
406 EF_USIM_ADF_map['ePDGSelection'], rpad('', len(res)))
407 elif sw == '9000':
408 (res, sw) = self._scc.update_binary(
409 EF_USIM_ADF_map['ePDGSelection'], enc_ePDGSelection(res, mcc, mnc))
410 return sw
Supreeth Herlef964df42020-03-24 13:15:37 +0100411
Harald Weltec91085e2022-02-10 18:05:45 +0100412 def read_ust(self):
413 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
414 if sw == '9000':
415 # Print those which are available
416 return ([res, dec_st(res, table="usim")], sw)
417 else:
418 return ([None, None], sw)
herlesupreeth4a3580b2020-09-29 10:11:36 +0200419
Harald Weltec91085e2022-02-10 18:05:45 +0100420 def update_ust(self, service, bit=1):
421 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
422 if sw == '9000':
423 content = enc_st(res, service, bit)
424 (res, sw) = self._scc.update_binary(
425 EF_USIM_ADF_map['UST'], content)
426 return sw
427
Supreeth Herleacc222f2020-03-24 13:26:53 +0100428
Philipp Maierbb73e512021-05-05 16:14:00 +0200429class IsimCard(SimCard):
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200430
Harald Weltec91085e2022-02-10 18:05:45 +0100431 name = 'ISIM'
Philipp Maierfc5f28d2021-05-05 12:18:41 +0200432
Harald Weltec91085e2022-02-10 18:05:45 +0100433 def __init__(self, ssc):
434 super(IsimCard, self).__init__(ssc)
herlesupreethecbada92020-12-23 09:24:29 +0100435
Harald Weltec91085e2022-02-10 18:05:45 +0100436 def read_pcscf(self):
437 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['PCSCF'])
438 pcscf_recs = ""
439 for i in range(0, rec_cnt):
440 (res, sw) = self._scc.read_record(EF_ISIM_ADF_map['PCSCF'], i + 1)
441 if sw == '9000':
442 try:
443 addr, addr_type = dec_addr_tlv(res)
444 except:
445 addr = None
446 addr_type = None
447 content = format_addr(addr, addr_type)
448 pcscf_recs += "%s" % (len(content)
449 and content or '\tNot available\n')
450 else:
451 pcscf_recs += "\tP-CSCF: Can't read, response code = %s\n" % (
452 sw)
453 return pcscf_recs
Supreeth Herle5ad9aec2020-03-24 17:26:40 +0100454
Harald Weltec91085e2022-02-10 18:05:45 +0100455 def update_pcscf(self, pcscf):
456 if len(pcscf) > 0:
457 addr_type = get_addr_type(pcscf)
458 if addr_type == None:
459 raise ValueError(
460 "Unknown PCSCF address type or invalid address provided")
461 content = enc_addr_tlv(pcscf, ('%02x' % addr_type))
462 else:
463 # Just the tag value
464 content = '80'
465 rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['PCSCF'])
466 pcscf_tlv = rpad(content, rec_size_bytes*2)
467 data, sw = self._scc.update_record(
468 EF_ISIM_ADF_map['PCSCF'], 1, pcscf_tlv)
469 return sw
Supreeth Herlecf727f22020-03-24 17:32:21 +0100470
Harald Weltec91085e2022-02-10 18:05:45 +0100471 def read_domain(self):
472 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['DOMAIN'])
473 if sw == '9000':
474 # Skip the initial tag value ('80') byte and get length of contents
475 length = int(res[2:4], 16)
476 content = h2s(res[4:4+(length*2)])
477 return (content, sw)
478 else:
479 return (None, sw)
Supreeth Herle05b28072020-03-25 10:23:48 +0100480
Harald Weltec91085e2022-02-10 18:05:45 +0100481 def update_domain(self, domain=None, mcc=None, mnc=None):
482 hex_str = ""
483 if domain:
484 hex_str = s2h(domain)
485 elif mcc and mnc:
486 # MCC and MNC always has 3 digits in domain form
487 plmn_str = 'mnc' + lpad(mnc, 3, "0") + '.mcc' + lpad(mcc, 3, "0")
488 hex_str = s2h('ims.' + plmn_str + '.3gppnetwork.org')
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100489
Harald Weltec91085e2022-02-10 18:05:45 +0100490 # Build TLV
491 tlv = TLV(['80'])
492 content = tlv.build({'80': hex_str})
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100493
Harald Weltec91085e2022-02-10 18:05:45 +0100494 bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['DOMAIN'])
495 data, sw = self._scc.update_binary(
496 EF_ISIM_ADF_map['DOMAIN'], rpad(content, bin_size_bytes*2))
497 return sw
Supreeth Herle79f43dd2020-03-25 11:43:19 +0100498
Harald Weltec91085e2022-02-10 18:05:45 +0100499 def read_impi(self):
500 (res, sw) = self._scc.read_binary(EF_ISIM_ADF_map['IMPI'])
501 if sw == '9000':
502 # Skip the initial tag value ('80') byte and get length of contents
503 length = int(res[2:4], 16)
504 content = h2s(res[4:4+(length*2)])
505 return (content, sw)
506 else:
507 return (None, sw)
Supreeth Herle3f67f9c2020-03-25 15:38:02 +0100508
Harald Weltec91085e2022-02-10 18:05:45 +0100509 def update_impi(self, impi=None):
510 hex_str = ""
511 if impi:
512 hex_str = s2h(impi)
513 # Build TLV
514 tlv = TLV(['80'])
515 content = tlv.build({'80': hex_str})
Supreeth Herlea5bd9682020-03-26 09:16:14 +0100516
Harald Weltec91085e2022-02-10 18:05:45 +0100517 bin_size_bytes = self._scc.binary_size(EF_ISIM_ADF_map['IMPI'])
518 data, sw = self._scc.update_binary(
519 EF_ISIM_ADF_map['IMPI'], rpad(content, bin_size_bytes*2))
520 return sw
Supreeth Herlea5bd9682020-03-26 09:16:14 +0100521
Harald Weltec91085e2022-02-10 18:05:45 +0100522 def read_impu(self):
523 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['IMPU'])
524 impu_recs = ""
525 for i in range(0, rec_cnt):
526 (res, sw) = self._scc.read_record(EF_ISIM_ADF_map['IMPU'], i + 1)
527 if sw == '9000':
528 # Skip the initial tag value ('80') byte and get length of contents
529 length = int(res[2:4], 16)
530 content = h2s(res[4:4+(length*2)])
531 impu_recs += "\t%s\n" % (len(content)
532 and content or 'Not available')
533 else:
534 impu_recs += "IMS public user identity: Can't read, response code = %s\n" % (
535 sw)
536 return impu_recs
Supreeth Herle0c02d8a2020-03-26 09:00:06 +0100537
Harald Weltec91085e2022-02-10 18:05:45 +0100538 def update_impu(self, impu=None):
539 hex_str = ""
540 if impu:
541 hex_str = s2h(impu)
542 # Build TLV
543 tlv = TLV(['80'])
544 content = tlv.build({'80': hex_str})
Supreeth Herlebe7007e2020-03-26 09:27:45 +0100545
Harald Weltec91085e2022-02-10 18:05:45 +0100546 rec_size_bytes = self._scc.record_size(EF_ISIM_ADF_map['IMPU'])
547 impu_tlv = rpad(content, rec_size_bytes*2)
548 data, sw = self._scc.update_record(
549 EF_ISIM_ADF_map['IMPU'], 1, impu_tlv)
550 return sw
Supreeth Herlebe7007e2020-03-26 09:27:45 +0100551
Harald Weltec91085e2022-02-10 18:05:45 +0100552 def read_iari(self):
553 rec_cnt = self._scc.record_count(EF_ISIM_ADF_map['UICCIARI'])
554 uiari_recs = ""
555 for i in range(0, rec_cnt):
556 (res, sw) = self._scc.read_record(
557 EF_ISIM_ADF_map['UICCIARI'], i + 1)
558 if sw == '9000':
559 # Skip the initial tag value ('80') byte and get length of contents
560 length = int(res[2:4], 16)
561 content = h2s(res[4:4+(length*2)])
562 uiari_recs += "\t%s\n" % (len(content)
563 and content or 'Not available')
564 else:
565 uiari_recs += "UICC IARI: Can't read, response code = %s\n" % (
566 sw)
567 return uiari_recs
568
Sylvain Munaut76504e02010-12-07 00:24:32 +0100569
Philipp Maierbb73e512021-05-05 16:14:00 +0200570class MagicSimBase(abc.ABC, SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100571 """
572 Theses cards uses several record based EFs to store the provider infos,
573 each possible provider uses a specific record number in each EF. The
574 indexes used are ( where N is the number of providers supported ) :
575 - [2 .. N+1] for the operator name
576 - [1 .. N] for the programmable EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100577
Harald Weltec91085e2022-02-10 18:05:45 +0100578 * 3f00/7f4d/8f0c : Operator Name
Sylvain Munaut76504e02010-12-07 00:24:32 +0100579
Harald Weltec91085e2022-02-10 18:05:45 +0100580 bytes 0-15 : provider name, padded with 0xff
581 byte 16 : length of the provider name
582 byte 17 : 01 for valid records, 00 otherwise
Sylvain Munaut76504e02010-12-07 00:24:32 +0100583
Harald Weltec91085e2022-02-10 18:05:45 +0100584 * 3f00/7f4d/8f0d : Programmable Binary EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100585
Harald Weltec91085e2022-02-10 18:05:45 +0100586 * 3f00/7f4d/8f0e : Programmable Record EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100587
Harald Weltec91085e2022-02-10 18:05:45 +0100588 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100589
Harald Weltec91085e2022-02-10 18:05:45 +0100590 _files = {} # type: Dict[str, Tuple[str, int, bool]]
591 _ki_file = None # type: Optional[str]
Vadim Yanitskiy03c67f72021-05-02 02:10:39 +0200592
Harald Weltec91085e2022-02-10 18:05:45 +0100593 @classmethod
594 def autodetect(kls, scc):
595 try:
596 for p, l, t in kls._files.values():
597 if not t:
598 continue
599 if scc.record_size(['3f00', '7f4d', p]) != l:
600 return None
601 except:
602 return None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100603
Harald Weltec91085e2022-02-10 18:05:45 +0100604 return kls(scc)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100605
Harald Weltec91085e2022-02-10 18:05:45 +0100606 def _get_count(self):
607 """
608 Selects the file and returns the total number of entries
609 and entry size
610 """
611 f = self._files['name']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100612
Harald Weltec91085e2022-02-10 18:05:45 +0100613 r = self._scc.select_path(['3f00', '7f4d', f[0]])
614 rec_len = int(r[-1][28:30], 16)
615 tlen = int(r[-1][4:8], 16)
616 rec_cnt = (tlen // rec_len) - 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100617
Harald Weltec91085e2022-02-10 18:05:45 +0100618 if (rec_cnt < 1) or (rec_len != f[1]):
619 raise RuntimeError('Bad card type')
Sylvain Munaut76504e02010-12-07 00:24:32 +0100620
Harald Weltec91085e2022-02-10 18:05:45 +0100621 return rec_cnt
Sylvain Munaut76504e02010-12-07 00:24:32 +0100622
Harald Weltec91085e2022-02-10 18:05:45 +0100623 def program(self, p):
624 # Go to dir
625 self._scc.select_path(['3f00', '7f4d'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100626
Harald Weltec91085e2022-02-10 18:05:45 +0100627 # Home PLMN in PLMN_Sel format
628 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100629
Harald Weltec91085e2022-02-10 18:05:45 +0100630 # Operator name ( 3f00/7f4d/8f0c )
631 self._scc.update_record(self._files['name'][0], 2,
632 rpad(b2h(p['name']), 32) + ('%02x' %
633 len(p['name'])) + '01'
634 )
Sylvain Munaut76504e02010-12-07 00:24:32 +0100635
Harald Weltec91085e2022-02-10 18:05:45 +0100636 # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
637 v = ''
Sylvain Munaut76504e02010-12-07 00:24:32 +0100638
Harald Weltec91085e2022-02-10 18:05:45 +0100639 # inline Ki
640 if self._ki_file is None:
641 v += p['ki']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100642
Harald Weltec91085e2022-02-10 18:05:45 +0100643 # ICCID
644 v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100645
Harald Weltec91085e2022-02-10 18:05:45 +0100646 # IMSI
647 v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100648
Harald Weltec91085e2022-02-10 18:05:45 +0100649 # Ki
650 if self._ki_file:
651 v += self._ki_file + '10' + p['ki']
Sylvain Munaut76504e02010-12-07 00:24:32 +0100652
Harald Weltec91085e2022-02-10 18:05:45 +0100653 # PLMN_Sel
654 v += '6f30' + '18' + rpad(hplmn, 36)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100655
Harald Weltec91085e2022-02-10 18:05:45 +0100656 # ACC
657 # This doesn't work with "fake" SuperSIM cards,
658 # but will hopefully work with real SuperSIMs.
659 if p.get('acc') is not None:
660 v += '6f78' + '02' + lpad(p['acc'], 4)
Alexander Chemeris21885242013-07-02 16:56:55 +0400661
Harald Weltec91085e2022-02-10 18:05:45 +0100662 self._scc.update_record(self._files['b_ef'][0], 1,
663 rpad(v, self._files['b_ef'][1]*2)
664 )
Sylvain Munaut76504e02010-12-07 00:24:32 +0100665
Harald Weltec91085e2022-02-10 18:05:45 +0100666 # SMSP ( 3f00/7f4d/8f0e )
667 # FIXME
Sylvain Munaut76504e02010-12-07 00:24:32 +0100668
Harald Weltec91085e2022-02-10 18:05:45 +0100669 # Write PLMN_Sel forcefully as well
670 r = self._scc.select_path(['3f00', '7f20', '6f30'])
671 tl = int(r[-1][4:8], 16)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100672
Harald Weltec91085e2022-02-10 18:05:45 +0100673 hplmn = enc_plmn(p['mcc'], p['mnc'])
674 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100675
Harald Weltec91085e2022-02-10 18:05:45 +0100676 def erase(self):
677 # Dummy
678 df = {}
679 for k, v in self._files.items():
680 ofs = 1
681 fv = v[1] * 'ff'
682 if k == 'name':
683 ofs = 2
684 fv = fv[0:-4] + '0000'
685 df[v[0]] = (fv, ofs)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100686
Harald Weltec91085e2022-02-10 18:05:45 +0100687 # Write
688 for n in range(0, self._get_count()):
689 for k, (msg, ofs) in df.items():
690 self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100691
692
Vadim Yanitskiy85302d62021-05-02 02:18:42 +0200693class SuperSim(MagicSimBase):
Sylvain Munaut76504e02010-12-07 00:24:32 +0100694
Harald Weltec91085e2022-02-10 18:05:45 +0100695 name = 'supersim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100696
Harald Weltec91085e2022-02-10 18:05:45 +0100697 _files = {
698 'name': ('8f0c', 18, True),
699 'b_ef': ('8f0d', 74, True),
700 'r_ef': ('8f0e', 50, True),
701 }
Sylvain Munaut76504e02010-12-07 00:24:32 +0100702
Harald Weltec91085e2022-02-10 18:05:45 +0100703 _ki_file = None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100704
705
Vadim Yanitskiy85302d62021-05-02 02:18:42 +0200706class MagicSim(MagicSimBase):
Sylvain Munaut76504e02010-12-07 00:24:32 +0100707
Harald Weltec91085e2022-02-10 18:05:45 +0100708 name = 'magicsim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100709
Harald Weltec91085e2022-02-10 18:05:45 +0100710 _files = {
711 'name': ('8f0c', 18, True),
712 'b_ef': ('8f0d', 130, True),
713 'r_ef': ('8f0e', 102, False),
714 }
Sylvain Munaut76504e02010-12-07 00:24:32 +0100715
Harald Weltec91085e2022-02-10 18:05:45 +0100716 _ki_file = '6f1b'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100717
718
Philipp Maierbb73e512021-05-05 16:14:00 +0200719class FakeMagicSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100720 """
721 Theses cards have a record based EF 3f00/000c that contains the provider
722 information. See the program method for its format. The records go from
723 1 to N.
724 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100725
Harald Weltec91085e2022-02-10 18:05:45 +0100726 name = 'fakemagicsim'
Sylvain Munaut76504e02010-12-07 00:24:32 +0100727
Harald Weltec91085e2022-02-10 18:05:45 +0100728 @classmethod
729 def autodetect(kls, scc):
730 try:
731 if scc.record_size(['3f00', '000c']) != 0x5a:
732 return None
733 except:
734 return None
Sylvain Munaut76504e02010-12-07 00:24:32 +0100735
Harald Weltec91085e2022-02-10 18:05:45 +0100736 return kls(scc)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100737
Harald Weltec91085e2022-02-10 18:05:45 +0100738 def _get_infos(self):
739 """
740 Selects the file and returns the total number of entries
741 and entry size
742 """
Sylvain Munaut76504e02010-12-07 00:24:32 +0100743
Harald Weltec91085e2022-02-10 18:05:45 +0100744 r = self._scc.select_path(['3f00', '000c'])
745 rec_len = int(r[-1][28:30], 16)
746 tlen = int(r[-1][4:8], 16)
747 rec_cnt = (tlen // rec_len) - 1
Sylvain Munaut76504e02010-12-07 00:24:32 +0100748
Harald Weltec91085e2022-02-10 18:05:45 +0100749 if (rec_cnt < 1) or (rec_len != 0x5a):
750 raise RuntimeError('Bad card type')
Sylvain Munaut76504e02010-12-07 00:24:32 +0100751
Harald Weltec91085e2022-02-10 18:05:45 +0100752 return rec_cnt, rec_len
Sylvain Munaut76504e02010-12-07 00:24:32 +0100753
Harald Weltec91085e2022-02-10 18:05:45 +0100754 def program(self, p):
755 # Home PLMN
756 r = self._scc.select_path(['3f00', '7f20', '6f30'])
757 tl = int(r[-1][4:8], 16)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100758
Harald Weltec91085e2022-02-10 18:05:45 +0100759 hplmn = enc_plmn(p['mcc'], p['mnc'])
760 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
Sylvain Munaut76504e02010-12-07 00:24:32 +0100761
Harald Weltec91085e2022-02-10 18:05:45 +0100762 # Get total number of entries and entry size
763 rec_cnt, rec_len = self._get_infos()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100764
Harald Weltec91085e2022-02-10 18:05:45 +0100765 # Set first entry
766 entry = (
767 '81' + # 1b Status: Valid & Active
768 rpad(s2h(p['name'][0:14]), 28) + # 14b Entry Name
769 enc_iccid(p['iccid']) + # 10b ICCID
770 enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
771 p['ki'] + # 16b Ki
772 lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
773 )
774 self._scc.update_record('000c', 1, entry)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100775
Harald Weltec91085e2022-02-10 18:05:45 +0100776 def erase(self):
777 # Get total number of entries and entry size
778 rec_cnt, rec_len = self._get_infos()
Sylvain Munaut76504e02010-12-07 00:24:32 +0100779
Harald Weltec91085e2022-02-10 18:05:45 +0100780 # Erase all entries
781 entry = 'ff' * rec_len
782 for i in range(0, rec_cnt):
783 self._scc.update_record('000c', 1+i, entry)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100784
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200785
Philipp Maierbb73e512021-05-05 16:14:00 +0200786class GrcardSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100787 """
788 Greencard (grcard.cn) HZCOS GSM SIM
789 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
790 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
791 """
Harald Welte3156d902011-03-22 21:48:19 +0100792
Harald Weltec91085e2022-02-10 18:05:45 +0100793 name = 'grcardsim'
Harald Welte3156d902011-03-22 21:48:19 +0100794
Harald Weltec91085e2022-02-10 18:05:45 +0100795 @classmethod
796 def autodetect(kls, scc):
797 return None
Harald Welte3156d902011-03-22 21:48:19 +0100798
Harald Weltec91085e2022-02-10 18:05:45 +0100799 def program(self, p):
800 # We don't really know yet what ADM PIN 4 is about
801 #self._scc.verify_chv(4, h2b("4444444444444444"))
Harald Welte3156d902011-03-22 21:48:19 +0100802
Harald Weltec91085e2022-02-10 18:05:45 +0100803 # Authenticate using ADM PIN 5
804 if p['pin_adm']:
805 pin = h2b(p['pin_adm'])
806 else:
807 pin = h2b("4444444444444444")
808 self._scc.verify_chv(5, pin)
Harald Welte3156d902011-03-22 21:48:19 +0100809
Harald Weltec91085e2022-02-10 18:05:45 +0100810 # EF.ICCID
811 r = self._scc.select_path(['3f00', '2fe2'])
812 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100813
Harald Weltec91085e2022-02-10 18:05:45 +0100814 # EF.IMSI
815 r = self._scc.select_path(['3f00', '7f20', '6f07'])
816 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100817
Harald Weltec91085e2022-02-10 18:05:45 +0100818 # EF.ACC
819 if p.get('acc') is not None:
820 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100821
Harald Weltec91085e2022-02-10 18:05:45 +0100822 # EF.SMSP
823 if p.get('smsp'):
824 r = self._scc.select_path(['3f00', '7f10', '6f42'])
825 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100826
Harald Weltec91085e2022-02-10 18:05:45 +0100827 # Set the Ki using proprietary command
828 pdu = '80d4020010' + p['ki']
829 data, sw = self._scc._tp.send_apdu(pdu)
Harald Welte3156d902011-03-22 21:48:19 +0100830
Harald Weltec91085e2022-02-10 18:05:45 +0100831 # EF.HPLMN
832 r = self._scc.select_path(['3f00', '7f20', '6f30'])
833 size = int(r[-1][4:8], 16)
834 hplmn = enc_plmn(p['mcc'], p['mnc'])
835 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
Harald Welte3156d902011-03-22 21:48:19 +0100836
Harald Weltec91085e2022-02-10 18:05:45 +0100837 # EF.SPN (Service Provider Name)
838 r = self._scc.select_path(['3f00', '7f20', '6f30'])
839 size = int(r[-1][4:8], 16)
840 # FIXME
Harald Welte3156d902011-03-22 21:48:19 +0100841
Harald Weltec91085e2022-02-10 18:05:45 +0100842 # FIXME: EF.MSISDN
Harald Welte3156d902011-03-22 21:48:19 +0100843
Sylvain Munaut76504e02010-12-07 00:24:32 +0100844
Harald Weltee10394b2011-12-07 12:34:14 +0100845class SysmoSIMgr1(GrcardSim):
Harald Weltec91085e2022-02-10 18:05:45 +0100846 """
847 sysmocom sysmoSIM-GR1
848 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
849 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
850 """
851 name = 'sysmosim-gr1'
Harald Weltee10394b2011-12-07 12:34:14 +0100852
Harald Weltec91085e2022-02-10 18:05:45 +0100853 @classmethod
854 def autodetect(kls, scc):
855 try:
856 # Look for ATR
857 if scc.get_atr() == toBytes("3B 99 18 00 11 88 22 33 44 55 66 77 60"):
858 return kls(scc)
859 except:
860 return None
861 return None
862
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200863
Harald Welteca673942020-06-03 15:19:40 +0200864class SysmoUSIMgr1(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100865 """
866 sysmocom sysmoUSIM-GR1
867 """
868 name = 'sysmoUSIM-GR1'
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100869
Harald Weltec91085e2022-02-10 18:05:45 +0100870 @classmethod
871 def autodetect(kls, scc):
872 # TODO: Access the ATR
873 return None
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100874
Harald Weltec91085e2022-02-10 18:05:45 +0100875 def program(self, p):
876 # TODO: check if verify_chv could be used or what it needs
877 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
878 # Unlock the card..
879 data, sw = self._scc._tp.send_apdu_checksw(
880 "0020000A083332323133323332")
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100881
Harald Weltec91085e2022-02-10 18:05:45 +0100882 # TODO: move into SimCardCommands
883 par = (p['ki'] + # 16b K
884 p['opc'] + # 32b OPC
885 enc_iccid(p['iccid']) + # 10b ICCID
886 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
887 )
888 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100889
Sylvain Munaut053c8952013-07-02 15:12:32 +0200890
Philipp Maierbb73e512021-05-05 16:14:00 +0200891class SysmoSIMgr2(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100892 """
893 sysmocom sysmoSIM-GR2
894 """
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100895
Harald Weltec91085e2022-02-10 18:05:45 +0100896 name = 'sysmoSIM-GR2'
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100897
Harald Weltec91085e2022-02-10 18:05:45 +0100898 @classmethod
899 def autodetect(kls, scc):
900 try:
901 # Look for ATR
902 if scc.get_atr() == toBytes("3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68"):
903 return kls(scc)
904 except:
905 return None
906 return None
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100907
Harald Weltec91085e2022-02-10 18:05:45 +0100908 def program(self, p):
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100909
Harald Weltec91085e2022-02-10 18:05:45 +0100910 # select MF
911 r = self._scc.select_path(['3f00'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200912
Harald Weltec91085e2022-02-10 18:05:45 +0100913 # authenticate as SUPER ADM using default key
914 self._scc.verify_chv(0x0b, h2b("3838383838383838"))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100915
Harald Weltec91085e2022-02-10 18:05:45 +0100916 # set ADM pin using proprietary command
917 # INS: D4
918 # P1: 3A for PIN, 3B for PUK
919 # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
920 # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
921 if p['pin_adm']:
922 pin = h2b(p['pin_adm'])
923 else:
924 pin = h2b("4444444444444444")
Jan Balkec3ebd332015-01-26 12:22:55 +0100925
Harald Weltec91085e2022-02-10 18:05:45 +0100926 pdu = 'A0D43A0508' + b2h(pin)
927 data, sw = self._scc._tp.send_apdu(pdu)
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200928
Harald Weltec91085e2022-02-10 18:05:45 +0100929 # authenticate as ADM (enough to write file, and can set PINs)
Jan Balkec3ebd332015-01-26 12:22:55 +0100930
Harald Weltec91085e2022-02-10 18:05:45 +0100931 self._scc.verify_chv(0x05, pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100932
Harald Weltec91085e2022-02-10 18:05:45 +0100933 # write EF.ICCID
934 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100935
Harald Weltec91085e2022-02-10 18:05:45 +0100936 # select DF_GSM
937 r = self._scc.select_path(['7f20'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200938
Harald Weltec91085e2022-02-10 18:05:45 +0100939 # write EF.IMSI
940 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100941
Harald Weltec91085e2022-02-10 18:05:45 +0100942 # write EF.ACC
943 if p.get('acc') is not None:
944 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100945
Harald Weltec91085e2022-02-10 18:05:45 +0100946 # get size and write EF.HPLMN
947 r = self._scc.select_path(['6f30'])
948 size = int(r[-1][4:8], 16)
949 hplmn = enc_plmn(p['mcc'], p['mnc'])
950 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100951
Harald Weltec91085e2022-02-10 18:05:45 +0100952 # set COMP128 version 0 in proprietary file
953 data, sw = self._scc.update_binary('0001', '001000')
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100954
Harald Weltec91085e2022-02-10 18:05:45 +0100955 # set Ki in proprietary file
956 data, sw = self._scc.update_binary('0001', p['ki'], 3)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100957
Harald Weltec91085e2022-02-10 18:05:45 +0100958 # select DF_TELECOM
959 r = self._scc.select_path(['3f00', '7f10'])
Daniel Willmann5d8cd9b2020-10-19 11:01:49 +0200960
Harald Weltec91085e2022-02-10 18:05:45 +0100961 # write EF.SMSP
962 if p.get('smsp'):
963 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100964
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100965
Harald Welteca673942020-06-03 15:19:40 +0200966class SysmoUSIMSJS1(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +0100967 """
968 sysmocom sysmoUSIM-SJS1
969 """
Jan Balke3e840672015-01-26 15:36:27 +0100970
Harald Weltec91085e2022-02-10 18:05:45 +0100971 name = 'sysmoUSIM-SJS1'
Jan Balke3e840672015-01-26 15:36:27 +0100972
Harald Weltec91085e2022-02-10 18:05:45 +0100973 def __init__(self, ssc):
974 super(SysmoUSIMSJS1, self).__init__(ssc)
975 self._scc.cla_byte = "00"
976 self._scc.sel_ctrl = "0004" # request an FCP
Jan Balke3e840672015-01-26 15:36:27 +0100977
Harald Weltec91085e2022-02-10 18:05:45 +0100978 @classmethod
979 def autodetect(kls, scc):
980 try:
981 # Look for ATR
982 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"):
983 return kls(scc)
984 except:
985 return None
986 return None
Jan Balke3e840672015-01-26 15:36:27 +0100987
Harald Weltec91085e2022-02-10 18:05:45 +0100988 def verify_adm(self, key):
989 # authenticate as ADM using default key (written on the card..)
990 if not key:
991 raise ValueError(
992 "Please provide a PIN-ADM as there is no default one")
993 (res, sw) = self._scc.verify_chv(0x0A, key)
994 return sw
Harald Weltea6704252021-01-08 20:19:11 +0100995
Harald Weltec91085e2022-02-10 18:05:45 +0100996 def program(self, p):
997 self.verify_adm(h2b(p['pin_adm']))
Jan Balke3e840672015-01-26 15:36:27 +0100998
Harald Weltec91085e2022-02-10 18:05:45 +0100999 # select MF
1000 r = self._scc.select_path(['3f00'])
Jan Balke3e840672015-01-26 15:36:27 +01001001
Harald Weltec91085e2022-02-10 18:05:45 +01001002 # write EF.ICCID
1003 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Philipp Maiere9604882017-03-21 17:24:31 +01001004
Harald Weltec91085e2022-02-10 18:05:45 +01001005 # select DF_GSM
1006 r = self._scc.select_path(['7f20'])
Jan Balke3e840672015-01-26 15:36:27 +01001007
Harald Weltec91085e2022-02-10 18:05:45 +01001008 # set Ki in proprietary file
1009 data, sw = self._scc.update_binary('00FF', p['ki'])
Jan Balke3e840672015-01-26 15:36:27 +01001010
Harald Weltec91085e2022-02-10 18:05:45 +01001011 # set OPc in proprietary file
1012 if 'opc' in p:
1013 content = "01" + p['opc']
1014 data, sw = self._scc.update_binary('00F7', content)
Jan Balke3e840672015-01-26 15:36:27 +01001015
Harald Weltec91085e2022-02-10 18:05:45 +01001016 # set Service Provider Name
1017 if p.get('name') is not None:
1018 self.update_spn(p['name'], True, True)
Supreeth Herle7947d922019-06-08 07:50:53 +02001019
Harald Weltec91085e2022-02-10 18:05:45 +01001020 if p.get('acc') is not None:
1021 self.update_acc(p['acc'])
Supreeth Herlec8796a32019-12-23 12:23:42 +01001022
Harald Weltec91085e2022-02-10 18:05:45 +01001023 # write EF.IMSI
1024 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Jan Balke3e840672015-01-26 15:36:27 +01001025
Harald Weltec91085e2022-02-10 18:05:45 +01001026 # EF.PLMNsel
1027 if p.get('mcc') and p.get('mnc'):
1028 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1029 if sw != '9000':
1030 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001031
Harald Weltec91085e2022-02-10 18:05:45 +01001032 # EF.PLMNwAcT
1033 if p.get('mcc') and p.get('mnc'):
1034 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1035 if sw != '9000':
1036 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001037
Harald Weltec91085e2022-02-10 18:05:45 +01001038 # EF.OPLMNwAcT
1039 if p.get('mcc') and p.get('mnc'):
1040 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1041 if sw != '9000':
1042 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001043
Harald Weltec91085e2022-02-10 18:05:45 +01001044 # EF.HPLMNwAcT
1045 if p.get('mcc') and p.get('mnc'):
1046 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1047 if sw != '9000':
1048 print("Programming HPLMNwAcT failed with code %s" % sw)
Supreeth Herlef442fb42020-01-21 12:47:32 +01001049
Harald Weltec91085e2022-02-10 18:05:45 +01001050 # EF.AD
1051 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1052 if p.get('mcc') and p.get('mnc'):
1053 mnc = p['mnc']
1054 else:
1055 mnc = None
1056 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1057 if sw != '9000':
1058 print("Programming AD failed with code %s" % sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +01001059
Harald Weltec91085e2022-02-10 18:05:45 +01001060 # EF.SMSP
1061 if p.get('smsp'):
1062 r = self._scc.select_path(['3f00', '7f10'])
1063 data, sw = self._scc.update_record(
1064 '6f42', 1, lpad(p['smsp'], 104), force_len=True)
Jan Balke3e840672015-01-26 15:36:27 +01001065
Harald Weltec91085e2022-02-10 18:05:45 +01001066 # EF.MSISDN
1067 # TODO: Alpha Identifier (currently 'ff'O * 20)
1068 # TODO: Capability/Configuration1 Record Identifier
1069 # TODO: Extension1 Record Identifier
1070 if p.get('msisdn') is not None:
1071 msisdn = enc_msisdn(p['msisdn'])
1072 data = 'ff' * 20 + msisdn
Supreeth Herle5a541012019-12-22 08:59:16 +01001073
Harald Weltec91085e2022-02-10 18:05:45 +01001074 r = self._scc.select_path(['3f00', '7f10'])
1075 data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
Supreeth Herle5a541012019-12-22 08:59:16 +01001076
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001077
herlesupreeth4a3580b2020-09-29 10:11:36 +02001078class FairwavesSIM(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001079 """
1080 FairwavesSIM
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001081
Harald Weltec91085e2022-02-10 18:05:45 +01001082 The SIM card is operating according to the standard.
1083 For Ki/OP/OPC programming the following files are additionally open for writing:
1084 3F00/7F20/FF01 – OP/OPC:
1085 byte 1 = 0x01, bytes 2-17: OPC;
1086 byte 1 = 0x00, bytes 2-17: OP;
1087 3F00/7F20/FF02: Ki
1088 """
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001089
Harald Weltec91085e2022-02-10 18:05:45 +01001090 name = 'Fairwaves-SIM'
1091 # Propriatary files
1092 _EF_num = {
1093 'Ki': 'FF02',
1094 'OP/OPC': 'FF01',
1095 }
1096 _EF = {
1097 'Ki': DF['GSM']+[_EF_num['Ki']],
1098 'OP/OPC': DF['GSM']+[_EF_num['OP/OPC']],
1099 }
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001100
Harald Weltec91085e2022-02-10 18:05:45 +01001101 def __init__(self, ssc):
1102 super(FairwavesSIM, self).__init__(ssc)
1103 self._adm_chv_num = 0x11
1104 self._adm2_chv_num = 0x12
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001105
Harald Weltec91085e2022-02-10 18:05:45 +01001106 @classmethod
1107 def autodetect(kls, scc):
1108 try:
1109 # Look for ATR
1110 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"):
1111 return kls(scc)
1112 except:
1113 return None
1114 return None
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001115
Harald Weltec91085e2022-02-10 18:05:45 +01001116 def verify_adm2(self, key):
1117 '''
1118 Authenticate with ADM2 key.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001119
Harald Weltec91085e2022-02-10 18:05:45 +01001120 Fairwaves SIM cards support hierarchical key structure and ADM2 key
1121 is a key which has access to proprietary files (Ki and OP/OPC).
1122 That said, ADM key inherits permissions of ADM2 key and thus we rarely
1123 need ADM2 key per se.
1124 '''
1125 (res, sw) = self._scc.verify_chv(self._adm2_chv_num, key)
1126 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001127
Harald Weltec91085e2022-02-10 18:05:45 +01001128 def read_ki(self):
1129 """
1130 Read Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001131
Harald Weltec91085e2022-02-10 18:05:45 +01001132 Requires ADM1 access level
1133 """
1134 return self._scc.read_binary(self._EF['Ki'])
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001135
Harald Weltec91085e2022-02-10 18:05:45 +01001136 def update_ki(self, ki):
1137 """
1138 Set Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001139
Harald Weltec91085e2022-02-10 18:05:45 +01001140 Requires ADM1 access level
1141 """
1142 data, sw = self._scc.update_binary(self._EF['Ki'], ki)
1143 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001144
Harald Weltec91085e2022-02-10 18:05:45 +01001145 def read_op_opc(self):
1146 """
1147 Read Ki in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001148
Harald Weltec91085e2022-02-10 18:05:45 +01001149 Requires ADM1 access level
1150 """
1151 (ef, sw) = self._scc.read_binary(self._EF['OP/OPC'])
1152 type = 'OP' if ef[0:2] == '00' else 'OPC'
1153 return ((type, ef[2:]), sw)
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001154
Harald Weltec91085e2022-02-10 18:05:45 +01001155 def update_op(self, op):
1156 """
1157 Set OP in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001158
Harald Weltec91085e2022-02-10 18:05:45 +01001159 Requires ADM1 access level
1160 """
1161 content = '00' + op
1162 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
1163 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001164
Harald Weltec91085e2022-02-10 18:05:45 +01001165 def update_opc(self, opc):
1166 """
1167 Set OPC in proprietary file.
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001168
Harald Weltec91085e2022-02-10 18:05:45 +01001169 Requires ADM1 access level
1170 """
1171 content = '01' + opc
1172 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
1173 return sw
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001174
Harald Weltec91085e2022-02-10 18:05:45 +01001175 def program(self, p):
1176 # For some reason the card programming only works when the card
1177 # is handled as a classic SIM, even though it is an USIM, so we
1178 # reconfigure the class byte and the select control field on
1179 # the fly. When the programming is done the original values are
1180 # restored.
1181 cla_byte_orig = self._scc.cla_byte
1182 sel_ctrl_orig = self._scc.sel_ctrl
1183 self._scc.cla_byte = "a0"
1184 self._scc.sel_ctrl = "0000"
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001185
Harald Weltec91085e2022-02-10 18:05:45 +01001186 try:
1187 self._program(p)
1188 finally:
1189 # restore original cla byte and sel ctrl
1190 self._scc.cla_byte = cla_byte_orig
1191 self._scc.sel_ctrl = sel_ctrl_orig
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001192
Harald Weltec91085e2022-02-10 18:05:45 +01001193 def _program(self, p):
1194 # authenticate as ADM1
1195 if not p['pin_adm']:
1196 raise ValueError(
1197 "Please provide a PIN-ADM as there is no default one")
1198 self.verify_adm(h2b(p['pin_adm']))
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001199
Harald Weltec91085e2022-02-10 18:05:45 +01001200 # TODO: Set operator name
1201 if p.get('smsp') is not None:
1202 sw = self.update_smsp(p['smsp'])
1203 if sw != '9000':
1204 print("Programming SMSP failed with code %s" % sw)
1205 # This SIM doesn't support changing ICCID
1206 if p.get('mcc') is not None and p.get('mnc') is not None:
1207 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1208 if sw != '9000':
1209 print("Programming MCC/MNC failed with code %s" % sw)
1210 if p.get('imsi') is not None:
1211 sw = self.update_imsi(p['imsi'])
1212 if sw != '9000':
1213 print("Programming IMSI failed with code %s" % sw)
1214 if p.get('ki') is not None:
1215 sw = self.update_ki(p['ki'])
1216 if sw != '9000':
1217 print("Programming Ki failed with code %s" % sw)
1218 if p.get('opc') is not None:
1219 sw = self.update_opc(p['opc'])
1220 if sw != '9000':
1221 print("Programming OPC failed with code %s" % sw)
1222 if p.get('acc') is not None:
1223 sw = self.update_acc(p['acc'])
1224 if sw != '9000':
1225 print("Programming ACC failed with code %s" % sw)
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001226
1227
Philipp Maierbb73e512021-05-05 16:14:00 +02001228class OpenCellsSim(SimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001229 """
1230 OpenCellsSim
Todd Neal9eeadfc2018-04-25 15:36:29 -05001231
Harald Weltec91085e2022-02-10 18:05:45 +01001232 """
Todd Neal9eeadfc2018-04-25 15:36:29 -05001233
Harald Weltec91085e2022-02-10 18:05:45 +01001234 name = 'OpenCells-SIM'
Todd Neal9eeadfc2018-04-25 15:36:29 -05001235
Harald Weltec91085e2022-02-10 18:05:45 +01001236 def __init__(self, ssc):
1237 super(OpenCellsSim, self).__init__(ssc)
1238 self._adm_chv_num = 0x0A
Todd Neal9eeadfc2018-04-25 15:36:29 -05001239
Harald Weltec91085e2022-02-10 18:05:45 +01001240 @classmethod
1241 def autodetect(kls, scc):
1242 try:
1243 # Look for ATR
1244 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"):
1245 return kls(scc)
1246 except:
1247 return None
1248 return None
Todd Neal9eeadfc2018-04-25 15:36:29 -05001249
Harald Weltec91085e2022-02-10 18:05:45 +01001250 def program(self, p):
1251 if not p['pin_adm']:
1252 raise ValueError(
1253 "Please provide a PIN-ADM as there is no default one")
1254 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001255
Harald Weltec91085e2022-02-10 18:05:45 +01001256 # select MF
1257 r = self._scc.select_path(['3f00'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001258
Harald Weltec91085e2022-02-10 18:05:45 +01001259 # write EF.ICCID
1260 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001261
Harald Weltec91085e2022-02-10 18:05:45 +01001262 r = self._scc.select_path(['7ff0'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001263
Harald Weltec91085e2022-02-10 18:05:45 +01001264 # set Ki in proprietary file
1265 data, sw = self._scc.update_binary('FF02', p['ki'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001266
Harald Weltec91085e2022-02-10 18:05:45 +01001267 # set OPC in proprietary file
1268 data, sw = self._scc.update_binary('FF01', p['opc'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001269
Harald Weltec91085e2022-02-10 18:05:45 +01001270 # select DF_GSM
1271 r = self._scc.select_path(['7f20'])
Todd Neal9eeadfc2018-04-25 15:36:29 -05001272
Harald Weltec91085e2022-02-10 18:05:45 +01001273 # write EF.IMSI
1274 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Todd Neal9eeadfc2018-04-25 15:36:29 -05001275
Todd Neal9eeadfc2018-04-25 15:36:29 -05001276
herlesupreeth4a3580b2020-09-29 10:11:36 +02001277class WavemobileSim(UsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001278 """
1279 WavemobileSim
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001280
Harald Weltec91085e2022-02-10 18:05:45 +01001281 """
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001282
Harald Weltec91085e2022-02-10 18:05:45 +01001283 name = 'Wavemobile-SIM'
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001284
Harald Weltec91085e2022-02-10 18:05:45 +01001285 def __init__(self, ssc):
1286 super(WavemobileSim, self).__init__(ssc)
1287 self._adm_chv_num = 0x0A
1288 self._scc.cla_byte = "00"
1289 self._scc.sel_ctrl = "0004" # request an FCP
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001290
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 C7 80 31 E0 73 F6 21 13 67 4D 45 16 00 43 01 00 8F"):
1296 return kls(scc)
1297 except:
1298 return None
1299 return None
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001300
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.verify_adm(h2b(p['pin_adm']))
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001306
Harald Weltec91085e2022-02-10 18:05:45 +01001307 # EF.ICCID
1308 # TODO: Add programming of the ICCID
1309 if p.get('iccid'):
1310 print(
1311 "Warning: Programming of the ICCID is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001312
Harald Weltec91085e2022-02-10 18:05:45 +01001313 # KI (Presumably a propritary file)
1314 # TODO: Add programming of KI
1315 if p.get('ki'):
1316 print(
1317 "Warning: Programming of the KI is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001318
Harald Weltec91085e2022-02-10 18:05:45 +01001319 # OPc (Presumably a propritary file)
1320 # TODO: Add programming of OPc
1321 if p.get('opc'):
1322 print(
1323 "Warning: Programming of the OPc is not implemented for this type of card.")
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001324
Harald Weltec91085e2022-02-10 18:05:45 +01001325 # EF.SMSP
1326 if p.get('smsp'):
1327 sw = self.update_smsp(p['smsp'])
1328 if sw != '9000':
1329 print("Programming SMSP failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001330
Harald Weltec91085e2022-02-10 18:05:45 +01001331 # EF.IMSI
1332 if p.get('imsi'):
1333 sw = self.update_imsi(p['imsi'])
1334 if sw != '9000':
1335 print("Programming IMSI failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001336
Harald Weltec91085e2022-02-10 18:05:45 +01001337 # EF.ACC
1338 if p.get('acc'):
1339 sw = self.update_acc(p['acc'])
1340 if sw != '9000':
1341 print("Programming ACC failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001342
Harald Weltec91085e2022-02-10 18:05:45 +01001343 # EF.PLMNsel
1344 if p.get('mcc') and p.get('mnc'):
1345 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1346 if sw != '9000':
1347 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001348
Harald Weltec91085e2022-02-10 18:05:45 +01001349 # EF.PLMNwAcT
1350 if p.get('mcc') and p.get('mnc'):
1351 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1352 if sw != '9000':
1353 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001354
Harald Weltec91085e2022-02-10 18:05:45 +01001355 # EF.OPLMNwAcT
1356 if p.get('mcc') and p.get('mnc'):
1357 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1358 if sw != '9000':
1359 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001360
Harald Weltec91085e2022-02-10 18:05:45 +01001361 # EF.AD
1362 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1363 if p.get('mcc') and p.get('mnc'):
1364 mnc = p['mnc']
1365 else:
1366 mnc = None
1367 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1368 if sw != '9000':
1369 print("Programming AD failed with code %s" % sw)
Philipp Maier6e507a72019-04-01 16:33:48 +02001370
Harald Weltec91085e2022-02-10 18:05:45 +01001371 return None
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001372
Todd Neal9eeadfc2018-04-25 15:36:29 -05001373
herlesupreethb0c7d122020-12-23 09:25:46 +01001374class SysmoISIMSJA2(UsimCard, IsimCard):
Harald Weltec91085e2022-02-10 18:05:45 +01001375 """
1376 sysmocom sysmoISIM-SJA2
1377 """
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001378
Harald Weltec91085e2022-02-10 18:05:45 +01001379 name = 'sysmoISIM-SJA2'
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001380
Harald Weltec91085e2022-02-10 18:05:45 +01001381 def __init__(self, ssc):
1382 super(SysmoISIMSJA2, self).__init__(ssc)
1383 self._scc.cla_byte = "00"
1384 self._scc.sel_ctrl = "0004" # request an FCP
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001385
Harald Weltec91085e2022-02-10 18:05:45 +01001386 @classmethod
1387 def autodetect(kls, scc):
1388 try:
1389 # Try card model #1
1390 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9"
1391 if scc.get_atr() == toBytes(atr):
1392 return kls(scc)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001393
Harald Weltec91085e2022-02-10 18:05:45 +01001394 # Try card model #2
1395 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2"
1396 if scc.get_atr() == toBytes(atr):
1397 return kls(scc)
Philipp Maierb3e11ea2020-03-11 12:32:44 +01001398
Harald Weltec91085e2022-02-10 18:05:45 +01001399 # Try card model #3
1400 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"
1401 if scc.get_atr() == toBytes(atr):
1402 return kls(scc)
1403 except:
1404 return None
1405 return None
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001406
Harald Weltec91085e2022-02-10 18:05:45 +01001407 def verify_adm(self, key):
1408 # authenticate as ADM using default key (written on the card..)
1409 if not key:
1410 raise ValueError(
1411 "Please provide a PIN-ADM as there is no default one")
1412 (res, sw) = self._scc.verify_chv(0x0A, key)
1413 return sw
Harald Weltea6704252021-01-08 20:19:11 +01001414
Harald Weltec91085e2022-02-10 18:05:45 +01001415 def program(self, p):
1416 self.verify_adm(h2b(p['pin_adm']))
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001417
Harald Weltec91085e2022-02-10 18:05:45 +01001418 # This type of card does not allow to reprogram the ICCID.
1419 # Reprogramming the ICCID would mess up the card os software
1420 # license management, so the ICCID must be kept at its factory
1421 # setting!
1422 if p.get('iccid'):
1423 print(
1424 "Warning: Programming of the ICCID is not implemented for this type of card.")
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001425
Harald Weltec91085e2022-02-10 18:05:45 +01001426 # select DF_GSM
1427 self._scc.select_path(['7f20'])
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001428
Harald Weltec91085e2022-02-10 18:05:45 +01001429 # set Service Provider Name
1430 if p.get('name') is not None:
1431 self.update_spn(p['name'], True, True)
Robert Falkenberg54595362021-04-06 12:04:34 +02001432
Harald Weltec91085e2022-02-10 18:05:45 +01001433 # write EF.IMSI
1434 if p.get('imsi'):
1435 self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001436
Harald Weltec91085e2022-02-10 18:05:45 +01001437 # EF.PLMNsel
1438 if p.get('mcc') and p.get('mnc'):
1439 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1440 if sw != '9000':
1441 print("Programming PLMNsel failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001442
Harald Weltec91085e2022-02-10 18:05:45 +01001443 # EF.PLMNwAcT
1444 if p.get('mcc') and p.get('mnc'):
1445 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1446 if sw != '9000':
1447 print("Programming PLMNwAcT failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001448
Harald Weltec91085e2022-02-10 18:05:45 +01001449 # EF.OPLMNwAcT
1450 if p.get('mcc') and p.get('mnc'):
1451 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1452 if sw != '9000':
1453 print("Programming OPLMNwAcT failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001454
Harald Weltec91085e2022-02-10 18:05:45 +01001455 # EF.HPLMNwAcT
1456 if p.get('mcc') and p.get('mnc'):
1457 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1458 if sw != '9000':
1459 print("Programming HPLMNwAcT failed with code %s" % sw)
Harald Welte32f0d412020-05-05 17:35:57 +02001460
Harald Weltec91085e2022-02-10 18:05:45 +01001461 # EF.AD
1462 if (p.get('mcc') and p.get('mnc')) or p.get('opmode'):
1463 if p.get('mcc') and p.get('mnc'):
1464 mnc = p['mnc']
1465 else:
1466 mnc = None
1467 sw = self.update_ad(mnc=mnc, opmode=p.get('opmode'))
1468 if sw != '9000':
1469 print("Programming AD failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001470
Harald Weltec91085e2022-02-10 18:05:45 +01001471 # EF.SMSP
1472 if p.get('smsp'):
1473 r = self._scc.select_path(['3f00', '7f10'])
1474 data, sw = self._scc.update_record(
1475 '6f42', 1, lpad(p['smsp'], 104), force_len=True)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001476
Harald Weltec91085e2022-02-10 18:05:45 +01001477 # EF.MSISDN
1478 # TODO: Alpha Identifier (currently 'ff'O * 20)
1479 # TODO: Capability/Configuration1 Record Identifier
1480 # TODO: Extension1 Record Identifier
1481 if p.get('msisdn') is not None:
1482 msisdn = enc_msisdn(p['msisdn'])
1483 content = 'ff' * 20 + msisdn
Supreeth Herlec6019232020-03-26 10:00:45 +01001484
Harald Weltec91085e2022-02-10 18:05:45 +01001485 r = self._scc.select_path(['3f00', '7f10'])
1486 data, sw = self._scc.update_record(
1487 '6F40', 1, content, force_len=True)
Supreeth Herlec6019232020-03-26 10:00:45 +01001488
Harald Weltec91085e2022-02-10 18:05:45 +01001489 # EF.ACC
1490 if p.get('acc'):
1491 sw = self.update_acc(p['acc'])
1492 if sw != '9000':
1493 print("Programming ACC failed with code %s" % sw)
Supreeth Herlea97944b2020-03-26 10:03:25 +01001494
Harald Weltec91085e2022-02-10 18:05:45 +01001495 # Populate AIDs
1496 self.read_aids()
Supreeth Herle80164052020-03-23 12:06:29 +01001497
Harald Weltec91085e2022-02-10 18:05:45 +01001498 # update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
1499 # hard linked to EF-USIM_AUTH_KEY)
1500 self._scc.select_path(['3f00'])
1501 self._scc.select_path(['a515'])
1502 if p.get('ki'):
1503 self._scc.update_binary('6f20', p['ki'], 1)
1504 if p.get('opc'):
1505 self._scc.update_binary('6f20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001506
Harald Weltec91085e2022-02-10 18:05:45 +01001507 # update EF-USIM_AUTH_KEY in ADF.ISIM
1508 data, sw = self.select_adf_by_aid(adf="isim")
1509 if sw == '9000':
1510 if p.get('ki'):
1511 self._scc.update_binary('af20', p['ki'], 1)
1512 if p.get('opc'):
1513 self._scc.update_binary('af20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001514
Harald Weltec91085e2022-02-10 18:05:45 +01001515 # update EF.P-CSCF in ADF.ISIM
1516 if self.file_exists(EF_ISIM_ADF_map['PCSCF']):
1517 if p.get('pcscf'):
1518 sw = self.update_pcscf(p['pcscf'])
1519 else:
1520 sw = self.update_pcscf("")
1521 if sw != '9000':
1522 print("Programming P-CSCF failed with code %s" % sw)
Supreeth Herlecf727f22020-03-24 17:32:21 +01001523
Harald Weltec91085e2022-02-10 18:05:45 +01001524 # update EF.DOMAIN in ADF.ISIM
1525 if self.file_exists(EF_ISIM_ADF_map['DOMAIN']):
1526 if p.get('ims_hdomain'):
1527 sw = self.update_domain(domain=p['ims_hdomain'])
1528 else:
1529 sw = self.update_domain()
Supreeth Herlecf727f22020-03-24 17:32:21 +01001530
Harald Weltec91085e2022-02-10 18:05:45 +01001531 if sw != '9000':
1532 print(
1533 "Programming Home Network Domain Name failed with code %s" % sw)
Supreeth Herle79f43dd2020-03-25 11:43:19 +01001534
Harald Weltec91085e2022-02-10 18:05:45 +01001535 # update EF.IMPI in ADF.ISIM
1536 # TODO: Validate IMPI input
1537 if self.file_exists(EF_ISIM_ADF_map['IMPI']):
1538 if p.get('impi'):
1539 sw = self.update_impi(p['impi'])
1540 else:
1541 sw = self.update_impi()
1542 if sw != '9000':
1543 print("Programming IMPI failed with code %s" % sw)
Supreeth Herle79f43dd2020-03-25 11:43:19 +01001544
Harald Weltec91085e2022-02-10 18:05:45 +01001545 # update EF.IMPU in ADF.ISIM
1546 # TODO: Validate IMPU input
1547 # Support multiple IMPU if there is enough space
1548 if self.file_exists(EF_ISIM_ADF_map['IMPU']):
1549 if p.get('impu'):
1550 sw = self.update_impu(p['impu'])
1551 else:
1552 sw = self.update_impu()
1553 if sw != '9000':
1554 print("Programming IMPU failed with code %s" % sw)
Supreeth Herlea5bd9682020-03-26 09:16:14 +01001555
Harald Weltec91085e2022-02-10 18:05:45 +01001556 data, sw = self.select_adf_by_aid(adf="usim")
1557 if sw == '9000':
1558 # update EF-USIM_AUTH_KEY in ADF.USIM
1559 if p.get('ki'):
1560 self._scc.update_binary('af20', p['ki'], 1)
1561 if p.get('opc'):
1562 self._scc.update_binary('af20', p['opc'], 17)
Supreeth Herlebe7007e2020-03-26 09:27:45 +01001563
Harald Weltec91085e2022-02-10 18:05:45 +01001564 # update EF.EHPLMN in ADF.USIM
1565 if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
1566 if p.get('mcc') and p.get('mnc'):
1567 sw = self.update_ehplmn(p['mcc'], p['mnc'])
1568 if sw != '9000':
1569 print("Programming EHPLMN failed with code %s" % sw)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001570
Harald Weltec91085e2022-02-10 18:05:45 +01001571 # update EF.ePDGId in ADF.USIM
1572 if self.file_exists(EF_USIM_ADF_map['ePDGId']):
1573 if p.get('epdgid'):
1574 sw = self.update_epdgid(p['epdgid'])
1575 else:
1576 sw = self.update_epdgid("")
1577 if sw != '9000':
1578 print("Programming ePDGId failed with code %s" % sw)
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001579
Harald Weltec91085e2022-02-10 18:05:45 +01001580 # update EF.ePDGSelection in ADF.USIM
1581 if self.file_exists(EF_USIM_ADF_map['ePDGSelection']):
1582 if p.get('epdgSelection'):
1583 epdg_plmn = p['epdgSelection']
1584 sw = self.update_ePDGSelection(
1585 epdg_plmn[:3], epdg_plmn[3:])
1586 else:
1587 sw = self.update_ePDGSelection("", "")
1588 if sw != '9000':
1589 print("Programming ePDGSelection failed with code %s" % sw)
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001590
Harald Weltec91085e2022-02-10 18:05:45 +01001591 # After successfully programming EF.ePDGId and EF.ePDGSelection,
1592 # Set service 106 and 107 as available in EF.UST
1593 # Disable service 95, 99, 115 if ISIM application is present
1594 if self.file_exists(EF_USIM_ADF_map['UST']):
1595 if p.get('epdgSelection') and p.get('epdgid'):
1596 sw = self.update_ust(106, 1)
1597 if sw != '9000':
1598 print("Programming UST failed with code %s" % sw)
1599 sw = self.update_ust(107, 1)
1600 if sw != '9000':
1601 print("Programming UST failed with code %s" % sw)
Supreeth Herlef964df42020-03-24 13:15:37 +01001602
Harald Weltec91085e2022-02-10 18:05:45 +01001603 sw = self.update_ust(95, 0)
1604 if sw != '9000':
1605 print("Programming UST failed with code %s" % sw)
1606 sw = self.update_ust(99, 0)
1607 if sw != '9000':
1608 print("Programming UST failed with code %s" % sw)
1609 sw = self.update_ust(115, 0)
1610 if sw != '9000':
1611 print("Programming UST failed with code %s" % sw)
Supreeth Herlef964df42020-03-24 13:15:37 +01001612
Harald Weltec91085e2022-02-10 18:05:45 +01001613 return
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001614
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001615
Todd Neal9eeadfc2018-04-25 15:36:29 -05001616# In order for autodetection ...
Harald Weltec91085e2022-02-10 18:05:45 +01001617_cards_classes = [FakeMagicSim, SuperSim, MagicSim, GrcardSim,
1618 SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
1619 FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2]
1620
Alexander Chemeris8ad124a2018-01-10 14:17:55 +09001621
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001622def card_detect(ctype, scc):
Harald Weltec91085e2022-02-10 18:05:45 +01001623 # Detect type if needed
1624 card = None
1625 ctypes = dict([(kls.name, kls) for kls in _cards_classes])
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001626
Harald Weltec91085e2022-02-10 18:05:45 +01001627 if ctype == "auto":
1628 for kls in _cards_classes:
1629 card = kls.autodetect(scc)
1630 if card:
1631 print("Autodetected card type: %s" % card.name)
1632 card.reset()
1633 break
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001634
Harald Weltec91085e2022-02-10 18:05:45 +01001635 if card is None:
1636 print("Autodetection failed")
1637 return None
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001638
Harald Weltec91085e2022-02-10 18:05:45 +01001639 elif ctype in ctypes:
1640 card = ctypes[ctype](scc)
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001641
Harald Weltec91085e2022-02-10 18:05:45 +01001642 else:
1643 raise ValueError("Unknown card type: %s" % ctype)
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001644
Harald Weltec91085e2022-02-10 18:05:45 +01001645 return card