blob: a67540fb5d5464bf76229eee4b9626ebde3a2615 [file] [log] [blame]
Sylvain Munaut76504e02010-12-07 00:24:32 +01001#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3
4""" pySim: Card programmation logic
5"""
6
7#
8# Copyright (C) 2009-2010 Sylvain Munaut <tnt@246tNt.com>
Harald Welte3156d902011-03-22 21:48:19 +01009# Copyright (C) 2011 Harald Welte <laforge@gnumonks.org>
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030010# Copyright (C) 2017 Alexander.Chemeris <Alexander.Chemeris@gmail.com>
Sylvain Munaut76504e02010-12-07 00:24:32 +010011#
12# This program is free software: you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by
14# the Free Software Foundation, either version 2 of the License, or
15# (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program. If not, see <http://www.gnu.org/licenses/>.
24#
25
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030026from pySim.ts_51_011 import EF, DF
Harald Welteca673942020-06-03 15:19:40 +020027from pySim.ts_31_102 import EF_USIM_ADF_map
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030028from pySim.utils import *
Alexander Chemeris8ad124a2018-01-10 14:17:55 +090029from smartcard.util import toBytes
Sylvain Munaut76504e02010-12-07 00:24:32 +010030
31class Card(object):
32
33 def __init__(self, scc):
34 self._scc = scc
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030035 self._adm_chv_num = 4
Supreeth Herlee4e98312020-03-18 11:33:14 +010036 self._aids = []
Sylvain Munaut76504e02010-12-07 00:24:32 +010037
Sylvain Munaut76504e02010-12-07 00:24:32 +010038 def reset(self):
39 self._scc.reset_card()
40
Philipp Maierd58c6322020-05-12 16:47:45 +020041 def erase(self):
42 print("warning: erasing is not supported for specified card type!")
43 return
44
Harald Welteca673942020-06-03 15:19:40 +020045 def file_exists(self, fid):
46 res_arr = self._scc.try_select_file(fid)
47 for res in res_arr:
Harald Welte1e424202020-08-31 15:04:19 +020048 if res[1] != '9000':
49 return False
Harald Welteca673942020-06-03 15:19:40 +020050 return True
51
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030052 def verify_adm(self, key):
53 '''
54 Authenticate with ADM key
55 '''
56 (res, sw) = self._scc.verify_chv(self._adm_chv_num, key)
57 return sw
58
59 def read_iccid(self):
60 (res, sw) = self._scc.read_binary(EF['ICCID'])
61 if sw == '9000':
62 return (dec_iccid(res), sw)
63 else:
64 return (None, sw)
65
66 def read_imsi(self):
67 (res, sw) = self._scc.read_binary(EF['IMSI'])
68 if sw == '9000':
69 return (dec_imsi(res), sw)
70 else:
71 return (None, sw)
72
73 def update_imsi(self, imsi):
74 data, sw = self._scc.update_binary(EF['IMSI'], enc_imsi(imsi))
75 return sw
76
77 def update_acc(self, acc):
78 data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4))
79 return sw
80
Supreeth Herlea850a472020-03-19 12:44:11 +010081 def read_hplmn_act(self):
82 (res, sw) = self._scc.read_binary(EF['HPLMNAcT'])
83 if sw == '9000':
84 return (format_xplmn_w_act(res), sw)
85 else:
86 return (None, sw)
87
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030088 def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
89 """
90 Update Home PLMN with access technology bit-field
91
92 See Section "10.3.37 EFHPLMNwAcT (HPLMN Selector with Access Technology)"
93 in ETSI TS 151 011 for the details of the access_tech field coding.
94 Some common values:
95 access_tech = '0080' # Only GSM is selected
96 access_tech = 'FFFF' # All technologues selected, even Reserved for Future Use ones
97 """
98 # get size and write EF.HPLMNwAcT
Supreeth Herle2d785972019-11-30 11:00:10 +010099 data = self._scc.read_binary(EF['HPLMNwAcT'], length=None, offset=0)
Vadim Yanitskiy9664b2e2020-02-27 01:49:51 +0700100 size = len(data[0]) // 2
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300101 hplmn = enc_plmn(mcc, mnc)
102 content = hplmn + access_tech
Vadim Yanitskiy9664b2e2020-02-27 01:49:51 +0700103 data, sw = self._scc.update_binary(EF['HPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300104 return sw
105
Supreeth Herle1757b262020-03-19 12:43:11 +0100106 def read_oplmn_act(self):
107 (res, sw) = self._scc.read_binary(EF['OPLMNwAcT'])
108 if sw == '9000':
109 return (format_xplmn_w_act(res), sw)
110 else:
111 return (None, sw)
112
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200113 def update_oplmn_act(self, mcc, mnc, access_tech='FFFF'):
114 """
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200115 See note in update_hplmn_act()
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200116 """
117 # get size and write EF.OPLMNwAcT
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200118 data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
Vadim Yanitskiy99affe12020-02-15 05:03:09 +0700119 size = len(data[0]) // 2
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200120 hplmn = enc_plmn(mcc, mnc)
121 content = hplmn + access_tech
Vadim Yanitskiy9664b2e2020-02-27 01:49:51 +0700122 data, sw = self._scc.update_binary(EF['OPLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200123 return sw
124
Supreeth Herle14084402020-03-19 12:42:10 +0100125 def read_plmn_act(self):
126 (res, sw) = self._scc.read_binary(EF['PLMNwAcT'])
127 if sw == '9000':
128 return (format_xplmn_w_act(res), sw)
129 else:
130 return (None, sw)
131
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200132 def update_plmn_act(self, mcc, mnc, access_tech='FFFF'):
133 """
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200134 See note in update_hplmn_act()
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200135 """
136 # get size and write EF.PLMNwAcT
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200137 data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
Vadim Yanitskiy99affe12020-02-15 05:03:09 +0700138 size = len(data[0]) // 2
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200139 hplmn = enc_plmn(mcc, mnc)
140 content = hplmn + access_tech
Vadim Yanitskiy9664b2e2020-02-27 01:49:51 +0700141 data, sw = self._scc.update_binary(EF['PLMNwAcT'], content + 'ffffff0000' * (size // 5 - 1))
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200142 return sw
143
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200144 def update_plmnsel(self, mcc, mnc):
145 data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
Vadim Yanitskiy99affe12020-02-15 05:03:09 +0700146 size = len(data[0]) // 2
Philipp Maier5bf42602018-07-11 23:23:40 +0200147 hplmn = enc_plmn(mcc, mnc)
Philipp Maieraf9ae8b2018-07-13 11:15:49 +0200148 data, sw = self._scc.update_binary(EF['PLMNsel'], hplmn + 'ff' * (size-3))
149 return sw
Philipp Maier5bf42602018-07-11 23:23:40 +0200150
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300151 def update_smsp(self, smsp):
152 data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 84))
153 return sw
154
Philipp Maieree908ae2019-03-21 16:21:12 +0100155 def update_ad(self, mnc):
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200156 #See also: 3GPP TS 31.102, chapter 4.2.18
157 mnclen = len(str(mnc))
158 if mnclen == 1:
159 mnclen = 2
160 if mnclen > 3:
Philipp Maieree908ae2019-03-21 16:21:12 +0100161 raise RuntimeError('unable to calculate proper mnclen')
162
Philipp Maier7f9f64a2020-05-11 21:28:52 +0200163 data, sw = self._scc.read_binary(EF['AD'], length=None, offset=0)
164
165 # Reset contents to EF.AD in case the file is uninintalized
166 if data.lower() == "ffffffff":
167 data = "00000000"
168
169 content = data[0:6] + "%02X" % mnclen
Philipp Maieree908ae2019-03-21 16:21:12 +0100170 data, sw = self._scc.update_binary(EF['AD'], content)
171 return sw
172
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300173 def read_spn(self):
174 (spn, sw) = self._scc.read_binary(EF['SPN'])
175 if sw == '9000':
176 return (dec_spn(spn), sw)
177 else:
178 return (None, sw)
179
180 def update_spn(self, name, hplmn_disp=False, oplmn_disp=False):
181 content = enc_spn(name, hplmn_disp, oplmn_disp)
182 data, sw = self._scc.update_binary(EF['SPN'], rpad(content, 32))
183 return sw
184
Supreeth Herled21349a2020-04-01 08:37:47 +0200185 def read_binary(self, ef, length=None, offset=0):
186 ef_path = ef in EF and EF[ef] or ef
187 return self._scc.read_binary(ef_path, length, offset)
188
Supreeth Herlead10d662020-04-01 08:43:08 +0200189 def read_record(self, ef, rec_no):
190 ef_path = ef in EF and EF[ef] or ef
191 return self._scc.read_record(ef_path, rec_no)
192
Supreeth Herle98a69272020-03-18 12:14:48 +0100193 def read_gid1(self):
194 (res, sw) = self._scc.read_binary(EF['GID1'])
195 if sw == '9000':
196 return (res, sw)
197 else:
198 return (None, sw)
199
Supreeth Herle6d66af62020-03-19 12:49:16 +0100200 def read_msisdn(self):
201 (res, sw) = self._scc.read_record(EF['MSISDN'], 1)
202 if sw == '9000':
203 return (dec_msisdn(res), sw)
204 else:
205 return (None, sw)
206
Supreeth Herlee4e98312020-03-18 11:33:14 +0100207 # Fetch all the AIDs present on UICC
208 def read_aids(self):
209 try:
210 # Find out how many records the EF.DIR has
211 # and store all the AIDs in the UICC
Sebastian Viviani0dc8f692020-05-29 00:14:55 +0100212 rec_cnt = self._scc.record_count(EF['DIR'])
Supreeth Herlee4e98312020-03-18 11:33:14 +0100213 for i in range(0, rec_cnt):
Sebastian Viviani0dc8f692020-05-29 00:14:55 +0100214 rec = self._scc.read_record(EF['DIR'], i + 1)
Supreeth Herlee4e98312020-03-18 11:33:14 +0100215 if (rec[0][0:2], rec[0][4:6]) == ('61', '4f') and len(rec[0]) > 12 \
216 and rec[0][8:8 + int(rec[0][6:8], 16) * 2] not in self._aids:
217 self._aids.append(rec[0][8:8 + int(rec[0][6:8], 16) * 2])
218 except Exception as e:
219 print("Can't read AIDs from SIM -- %s" % (str(e),))
220
Supreeth Herlef9f3e5e2020-03-22 08:04:59 +0100221 # Select ADF.U/ISIM in the Card using its full AID
222 def select_adf_by_aid(self, adf="usim"):
223 # Check for valid ADF name
224 if adf not in ["usim", "isim"]:
225 return None
226
227 # First (known) halves of the U/ISIM AID
228 aid_map = {}
229 aid_map["usim"] = "a0000000871002"
230 aid_map["isim"] = "a0000000871004"
231
232 for aid in self._aids:
233 if aid_map[adf] in aid:
234 (res, sw) = self._scc.select_adf(aid)
235 return sw
236
237 return None
238
Philipp Maier5c2cc662020-05-12 16:27:12 +0200239 # Erase the contents of a file
240 def erase_binary(self, ef):
241 len = self._scc.binary_size(ef)
242 self._scc.update_binary(ef, "ff" * len, offset=0, verify=True)
243
244 # Erase the contents of a single record
245 def erase_record(self, ef, rec_no):
246 len = self._scc.record_size(ef)
247 self._scc.update_record(ef, rec_no, "ff" * len, force_len=False, verify=True)
248
Harald Welteca673942020-06-03 15:19:40 +0200249class UsimCard(Card):
250 def __init__(self, ssc):
251 super(UsimCard, self).__init__(ssc)
252
253 def read_ehplmn(self):
254 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'])
255 if sw == '9000':
256 return (format_xplmn(res), sw)
257 else:
258 return (None, sw)
259
260 def update_ehplmn(self, mcc, mnc):
261 data = self._scc.read_binary(EF_USIM_ADF_map['EHPLMN'], length=None, offset=0)
262 size = len(data[0]) // 2
263 ehplmn = enc_plmn(mcc, mnc)
264 data, sw = self._scc.update_binary(EF_USIM_ADF_map['EHPLMN'], ehplmn)
265 return sw
266
herlesupreethf8232db2020-09-29 10:03:06 +0200267 def read_epdgid(self):
268 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['ePDGId'])
269 if sw == '9000':
270 return (dec_epdgid(res), sw)
271 else:
272 return (None, sw)
273
herlesupreeth5d0a30c2020-09-29 09:44:24 +0200274 def update_epdgid(self, epdgid):
275 epdgid_tlv = enc_epdgid(epdgid)
276 data, sw = self._scc.update_binary(
277 EF_USIM_ADF_map['ePDGId'], epdgid_tlv)
278 return sw
Harald Welteca673942020-06-03 15:19:40 +0200279
herlesupreeth4a3580b2020-09-29 10:11:36 +0200280 def read_ust(self):
281 (res, sw) = self._scc.read_binary(EF_USIM_ADF_map['UST'])
282 if sw == '9000':
283 # Print those which are available
284 return ([res, dec_st(res, table="usim")], sw)
285 else:
286 return ([None, None], sw)
287
Sylvain Munaut76504e02010-12-07 00:24:32 +0100288
289class _MagicSimBase(Card):
290 """
291 Theses cards uses several record based EFs to store the provider infos,
292 each possible provider uses a specific record number in each EF. The
293 indexes used are ( where N is the number of providers supported ) :
294 - [2 .. N+1] for the operator name
Supreeth Herle9ca41c12020-01-21 12:50:30 +0100295 - [1 .. N] for the programable EFs
Sylvain Munaut76504e02010-12-07 00:24:32 +0100296
297 * 3f00/7f4d/8f0c : Operator Name
298
299 bytes 0-15 : provider name, padded with 0xff
300 byte 16 : length of the provider name
301 byte 17 : 01 for valid records, 00 otherwise
302
303 * 3f00/7f4d/8f0d : Programmable Binary EFs
304
305 * 3f00/7f4d/8f0e : Programmable Record EFs
306
307 """
308
309 @classmethod
310 def autodetect(kls, scc):
311 try:
312 for p, l, t in kls._files.values():
313 if not t:
314 continue
315 if scc.record_size(['3f00', '7f4d', p]) != l:
316 return None
317 except:
318 return None
319
320 return kls(scc)
321
322 def _get_count(self):
323 """
324 Selects the file and returns the total number of entries
325 and entry size
326 """
327 f = self._files['name']
328
329 r = self._scc.select_file(['3f00', '7f4d', f[0]])
330 rec_len = int(r[-1][28:30], 16)
331 tlen = int(r[-1][4:8],16)
332 rec_cnt = (tlen / rec_len) - 1;
333
334 if (rec_cnt < 1) or (rec_len != f[1]):
335 raise RuntimeError('Bad card type')
336
337 return rec_cnt
338
339 def program(self, p):
340 # Go to dir
341 self._scc.select_file(['3f00', '7f4d'])
342
343 # Home PLMN in PLMN_Sel format
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400344 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100345
346 # Operator name ( 3f00/7f4d/8f0c )
347 self._scc.update_record(self._files['name'][0], 2,
348 rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01'
349 )
350
351 # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
352 v = ''
353
354 # inline Ki
355 if self._ki_file is None:
356 v += p['ki']
357
358 # ICCID
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400359 v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100360
361 # IMSI
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400362 v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100363
364 # Ki
365 if self._ki_file:
366 v += self._ki_file + '10' + p['ki']
367
368 # PLMN_Sel
369 v+= '6f30' + '18' + rpad(hplmn, 36)
370
Alexander Chemeris21885242013-07-02 16:56:55 +0400371 # ACC
372 # This doesn't work with "fake" SuperSIM cards,
373 # but will hopefully work with real SuperSIMs.
374 if p.get('acc') is not None:
375 v+= '6f78' + '02' + lpad(p['acc'], 4)
376
Sylvain Munaut76504e02010-12-07 00:24:32 +0100377 self._scc.update_record(self._files['b_ef'][0], 1,
378 rpad(v, self._files['b_ef'][1]*2)
379 )
380
381 # SMSP ( 3f00/7f4d/8f0e )
382 # FIXME
383
384 # Write PLMN_Sel forcefully as well
385 r = self._scc.select_file(['3f00', '7f20', '6f30'])
386 tl = int(r[-1][4:8], 16)
387
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400388 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100389 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
390
391 def erase(self):
392 # Dummy
393 df = {}
394 for k, v in self._files.iteritems():
395 ofs = 1
396 fv = v[1] * 'ff'
397 if k == 'name':
398 ofs = 2
399 fv = fv[0:-4] + '0000'
400 df[v[0]] = (fv, ofs)
401
402 # Write
403 for n in range(0,self._get_count()):
404 for k, (msg, ofs) in df.iteritems():
405 self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
406
407
408class SuperSim(_MagicSimBase):
409
410 name = 'supersim'
411
412 _files = {
413 'name' : ('8f0c', 18, True),
414 'b_ef' : ('8f0d', 74, True),
415 'r_ef' : ('8f0e', 50, True),
416 }
417
418 _ki_file = None
419
420
421class MagicSim(_MagicSimBase):
422
423 name = 'magicsim'
424
425 _files = {
426 'name' : ('8f0c', 18, True),
427 'b_ef' : ('8f0d', 130, True),
428 'r_ef' : ('8f0e', 102, False),
429 }
430
431 _ki_file = '6f1b'
432
433
434class FakeMagicSim(Card):
435 """
436 Theses cards have a record based EF 3f00/000c that contains the provider
437 informations. See the program method for its format. The records go from
438 1 to N.
439 """
440
441 name = 'fakemagicsim'
442
443 @classmethod
444 def autodetect(kls, scc):
445 try:
446 if scc.record_size(['3f00', '000c']) != 0x5a:
447 return None
448 except:
449 return None
450
451 return kls(scc)
452
453 def _get_infos(self):
454 """
455 Selects the file and returns the total number of entries
456 and entry size
457 """
458
459 r = self._scc.select_file(['3f00', '000c'])
460 rec_len = int(r[-1][28:30], 16)
461 tlen = int(r[-1][4:8],16)
462 rec_cnt = (tlen / rec_len) - 1;
463
464 if (rec_cnt < 1) or (rec_len != 0x5a):
465 raise RuntimeError('Bad card type')
466
467 return rec_cnt, rec_len
468
469 def program(self, p):
470 # Home PLMN
471 r = self._scc.select_file(['3f00', '7f20', '6f30'])
472 tl = int(r[-1][4:8], 16)
473
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400474 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100475 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
476
477 # Get total number of entries and entry size
478 rec_cnt, rec_len = self._get_infos()
479
480 # Set first entry
481 entry = (
Philipp Maier45daa922019-04-01 15:49:45 +0200482 '81' + # 1b Status: Valid & Active
Sylvain Munaut76504e02010-12-07 00:24:32 +0100483 rpad(b2h(p['name'][0:14]), 28) + # 14b Entry Name
Philipp Maier45daa922019-04-01 15:49:45 +0200484 enc_iccid(p['iccid']) + # 10b ICCID
485 enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
486 p['ki'] + # 16b Ki
487 lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100488 )
489 self._scc.update_record('000c', 1, entry)
490
491 def erase(self):
492 # Get total number of entries and entry size
493 rec_cnt, rec_len = self._get_infos()
494
495 # Erase all entries
496 entry = 'ff' * rec_len
497 for i in range(0, rec_cnt):
498 self._scc.update_record('000c', 1+i, entry)
499
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200500
Harald Welte3156d902011-03-22 21:48:19 +0100501class GrcardSim(Card):
502 """
503 Greencard (grcard.cn) HZCOS GSM SIM
504 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
505 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
506 """
507
508 name = 'grcardsim'
509
510 @classmethod
511 def autodetect(kls, scc):
512 return None
513
514 def program(self, p):
515 # We don't really know yet what ADM PIN 4 is about
516 #self._scc.verify_chv(4, h2b("4444444444444444"))
517
518 # Authenticate using ADM PIN 5
Jan Balkec3ebd332015-01-26 12:22:55 +0100519 if p['pin_adm']:
Philipp Maiera3de5a32018-08-23 10:27:04 +0200520 pin = h2b(p['pin_adm'])
Jan Balkec3ebd332015-01-26 12:22:55 +0100521 else:
522 pin = h2b("4444444444444444")
523 self._scc.verify_chv(5, pin)
Harald Welte3156d902011-03-22 21:48:19 +0100524
525 # EF.ICCID
526 r = self._scc.select_file(['3f00', '2fe2'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400527 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100528
529 # EF.IMSI
530 r = self._scc.select_file(['3f00', '7f20', '6f07'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400531 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100532
533 # EF.ACC
Alexander Chemeris21885242013-07-02 16:56:55 +0400534 if p.get('acc') is not None:
535 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100536
537 # EF.SMSP
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200538 if p.get('smsp'):
Harald Welte23888da2019-08-28 23:19:11 +0200539 r = self._scc.select_file(['3f00', '7f10', '6f42'])
540 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100541
542 # Set the Ki using proprietary command
543 pdu = '80d4020010' + p['ki']
544 data, sw = self._scc._tp.send_apdu(pdu)
545
546 # EF.HPLMN
547 r = self._scc.select_file(['3f00', '7f20', '6f30'])
548 size = int(r[-1][4:8], 16)
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400549 hplmn = enc_plmn(p['mcc'], p['mnc'])
Harald Welte3156d902011-03-22 21:48:19 +0100550 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
551
552 # EF.SPN (Service Provider Name)
553 r = self._scc.select_file(['3f00', '7f20', '6f30'])
554 size = int(r[-1][4:8], 16)
555 # FIXME
556
557 # FIXME: EF.MSISDN
558
Sylvain Munaut76504e02010-12-07 00:24:32 +0100559
Harald Weltee10394b2011-12-07 12:34:14 +0100560class SysmoSIMgr1(GrcardSim):
561 """
562 sysmocom sysmoSIM-GR1
563 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
564 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
565 """
566 name = 'sysmosim-gr1'
567
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200568 @classmethod
Philipp Maier087feff2018-08-23 09:41:36 +0200569 def autodetect(kls, scc):
570 try:
571 # Look for ATR
572 if scc.get_atr() == toBytes("3B 99 18 00 11 88 22 33 44 55 66 77 60"):
573 return kls(scc)
574 except:
575 return None
576 return None
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200577
Harald Welteca673942020-06-03 15:19:40 +0200578class SysmoUSIMgr1(UsimCard):
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100579 """
580 sysmocom sysmoUSIM-GR1
581 """
582 name = 'sysmoUSIM-GR1'
583
584 @classmethod
585 def autodetect(kls, scc):
586 # TODO: Access the ATR
587 return None
588
589 def program(self, p):
590 # TODO: check if verify_chv could be used or what it needs
591 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
592 # Unlock the card..
593 data, sw = self._scc._tp.send_apdu_checksw("0020000A083332323133323332")
594
595 # TODO: move into SimCardCommands
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100596 par = ( p['ki'] + # 16b K
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400597 p['opc'] + # 32b OPC
598 enc_iccid(p['iccid']) + # 10b ICCID
599 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100600 )
601 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
602
Sylvain Munaut053c8952013-07-02 15:12:32 +0200603
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100604class SysmoSIMgr2(Card):
605 """
606 sysmocom sysmoSIM-GR2
607 """
608
609 name = 'sysmoSIM-GR2'
610
611 @classmethod
612 def autodetect(kls, scc):
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900613 try:
614 # Look for ATR
615 if scc.get_atr() == toBytes("3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68"):
616 return kls(scc)
617 except:
618 return None
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100619 return None
620
621 def program(self, p):
622
623 # select MF
624 r = self._scc.select_file(['3f00'])
625
626 # authenticate as SUPER ADM using default key
627 self._scc.verify_chv(0x0b, h2b("3838383838383838"))
628
629 # set ADM pin using proprietary command
630 # INS: D4
631 # P1: 3A for PIN, 3B for PUK
632 # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
633 # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
Jan Balkec3ebd332015-01-26 12:22:55 +0100634 if p['pin_adm']:
Daniel Willmann7d38d742018-06-15 07:31:50 +0200635 pin = h2b(p['pin_adm'])
Jan Balkec3ebd332015-01-26 12:22:55 +0100636 else:
637 pin = h2b("4444444444444444")
638
639 pdu = 'A0D43A0508' + b2h(pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100640 data, sw = self._scc._tp.send_apdu(pdu)
641
642 # authenticate as ADM (enough to write file, and can set PINs)
Jan Balkec3ebd332015-01-26 12:22:55 +0100643
644 self._scc.verify_chv(0x05, pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100645
646 # write EF.ICCID
647 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
648
649 # select DF_GSM
650 r = self._scc.select_file(['7f20'])
651
652 # write EF.IMSI
653 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
654
655 # write EF.ACC
656 if p.get('acc') is not None:
657 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
658
659 # get size and write EF.HPLMN
660 r = self._scc.select_file(['6f30'])
661 size = int(r[-1][4:8], 16)
662 hplmn = enc_plmn(p['mcc'], p['mnc'])
663 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
664
665 # set COMP128 version 0 in proprietary file
666 data, sw = self._scc.update_binary('0001', '001000')
667
668 # set Ki in proprietary file
669 data, sw = self._scc.update_binary('0001', p['ki'], 3)
670
671 # select DF_TELECOM
672 r = self._scc.select_file(['3f00', '7f10'])
673
674 # write EF.SMSP
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200675 if p.get('smsp'):
Harald Welte23888da2019-08-28 23:19:11 +0200676 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100677
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100678
Harald Welteca673942020-06-03 15:19:40 +0200679class SysmoUSIMSJS1(UsimCard):
Jan Balke3e840672015-01-26 15:36:27 +0100680 """
681 sysmocom sysmoUSIM-SJS1
682 """
683
684 name = 'sysmoUSIM-SJS1'
685
686 def __init__(self, ssc):
687 super(SysmoUSIMSJS1, self).__init__(ssc)
688 self._scc.cla_byte = "00"
Philipp Maier2d15ea02019-03-20 12:40:36 +0100689 self._scc.sel_ctrl = "0004" #request an FCP
Jan Balke3e840672015-01-26 15:36:27 +0100690
691 @classmethod
692 def autodetect(kls, scc):
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900693 try:
694 # Look for ATR
695 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"):
696 return kls(scc)
697 except:
698 return None
Jan Balke3e840672015-01-26 15:36:27 +0100699 return None
700
701 def program(self, p):
702
Philipp Maiere9604882017-03-21 17:24:31 +0100703 # authenticate as ADM using default key (written on the card..)
704 if not p['pin_adm']:
705 raise ValueError("Please provide a PIN-ADM as there is no default one")
706 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
Jan Balke3e840672015-01-26 15:36:27 +0100707
708 # select MF
709 r = self._scc.select_file(['3f00'])
710
Philipp Maiere9604882017-03-21 17:24:31 +0100711 # write EF.ICCID
712 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
713
Jan Balke3e840672015-01-26 15:36:27 +0100714 # select DF_GSM
715 r = self._scc.select_file(['7f20'])
716
Jan Balke3e840672015-01-26 15:36:27 +0100717 # set Ki in proprietary file
718 data, sw = self._scc.update_binary('00FF', p['ki'])
719
Philipp Maier1be35bf2018-07-13 11:29:03 +0200720 # set OPc in proprietary file
Daniel Willmann67acdbc2018-06-15 07:42:48 +0200721 if 'opc' in p:
722 content = "01" + p['opc']
723 data, sw = self._scc.update_binary('00F7', content)
Jan Balke3e840672015-01-26 15:36:27 +0100724
Supreeth Herle7947d922019-06-08 07:50:53 +0200725 # set Service Provider Name
Supreeth Herle840a9e22020-01-21 13:32:46 +0100726 if p.get('name') is not None:
727 content = enc_spn(p['name'], True, True)
728 data, sw = self._scc.update_binary('6F46', rpad(content, 32))
Supreeth Herle7947d922019-06-08 07:50:53 +0200729
Supreeth Herlec8796a32019-12-23 12:23:42 +0100730 if p.get('acc') is not None:
731 self.update_acc(p['acc'])
732
Jan Balke3e840672015-01-26 15:36:27 +0100733 # write EF.IMSI
734 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
735
Philipp Maier2d15ea02019-03-20 12:40:36 +0100736 # EF.PLMNsel
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200737 if p.get('mcc') and p.get('mnc'):
738 sw = self.update_plmnsel(p['mcc'], p['mnc'])
739 if sw != '9000':
Philipp Maier2d15ea02019-03-20 12:40:36 +0100740 print("Programming PLMNsel failed with code %s"%sw)
741
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200742 # EF.PLMNwAcT
743 if p.get('mcc') and p.get('mnc'):
Philipp Maier2d15ea02019-03-20 12:40:36 +0100744 sw = self.update_plmn_act(p['mcc'], p['mnc'])
745 if sw != '9000':
746 print("Programming PLMNwAcT failed with code %s"%sw)
747
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200748 # EF.OPLMNwAcT
749 if p.get('mcc') and p.get('mnc'):
Philipp Maier2d15ea02019-03-20 12:40:36 +0100750 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
751 if sw != '9000':
752 print("Programming OPLMNwAcT failed with code %s"%sw)
753
Supreeth Herlef442fb42020-01-21 12:47:32 +0100754 # EF.HPLMNwAcT
755 if p.get('mcc') and p.get('mnc'):
756 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
757 if sw != '9000':
758 print("Programming HPLMNwAcT failed with code %s"%sw)
759
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +0200760 # EF.AD
761 if p.get('mcc') and p.get('mnc'):
Philipp Maieree908ae2019-03-21 16:21:12 +0100762 sw = self.update_ad(p['mnc'])
763 if sw != '9000':
764 print("Programming AD failed with code %s"%sw)
Philipp Maier2d15ea02019-03-20 12:40:36 +0100765
Daniel Willmann1d087ef2017-08-31 10:08:45 +0200766 # EF.SMSP
Harald Welte23888da2019-08-28 23:19:11 +0200767 if p.get('smsp'):
768 r = self._scc.select_file(['3f00', '7f10'])
769 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
Jan Balke3e840672015-01-26 15:36:27 +0100770
Supreeth Herle5a541012019-12-22 08:59:16 +0100771 # EF.MSISDN
772 # TODO: Alpha Identifier (currently 'ff'O * 20)
773 # TODO: Capability/Configuration1 Record Identifier
774 # TODO: Extension1 Record Identifier
775 if p.get('msisdn') is not None:
776 msisdn = enc_msisdn(p['msisdn'])
777 data = 'ff' * 20 + msisdn + 'ff' * 2
778
779 r = self._scc.select_file(['3f00', '7f10'])
780 data, sw = self._scc.update_record('6F40', 1, data, force_len=True)
781
Alexander Chemerise0d9d882018-01-10 14:18:32 +0900782
herlesupreeth4a3580b2020-09-29 10:11:36 +0200783class FairwavesSIM(UsimCard):
Alexander Chemerise0d9d882018-01-10 14:18:32 +0900784 """
785 FairwavesSIM
786
787 The SIM card is operating according to the standard.
788 For Ki/OP/OPC programming the following files are additionally open for writing:
789 3F00/7F20/FF01 – OP/OPC:
790 byte 1 = 0x01, bytes 2-17: OPC;
791 byte 1 = 0x00, bytes 2-17: OP;
792 3F00/7F20/FF02: Ki
793 """
794
Philipp Maier5a876312019-11-11 11:01:46 +0100795 name = 'Fairwaves-SIM'
Alexander Chemerise0d9d882018-01-10 14:18:32 +0900796 # Propriatary files
797 _EF_num = {
798 'Ki': 'FF02',
799 'OP/OPC': 'FF01',
800 }
801 _EF = {
802 'Ki': DF['GSM']+[_EF_num['Ki']],
803 'OP/OPC': DF['GSM']+[_EF_num['OP/OPC']],
804 }
805
806 def __init__(self, ssc):
807 super(FairwavesSIM, self).__init__(ssc)
808 self._adm_chv_num = 0x11
809 self._adm2_chv_num = 0x12
810
811
812 @classmethod
813 def autodetect(kls, scc):
814 try:
815 # Look for ATR
816 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"):
817 return kls(scc)
818 except:
819 return None
820 return None
821
822
823 def verify_adm2(self, key):
824 '''
825 Authenticate with ADM2 key.
826
827 Fairwaves SIM cards support hierarchical key structure and ADM2 key
828 is a key which has access to proprietary files (Ki and OP/OPC).
829 That said, ADM key inherits permissions of ADM2 key and thus we rarely
830 need ADM2 key per se.
831 '''
832 (res, sw) = self._scc.verify_chv(self._adm2_chv_num, key)
833 return sw
834
835
836 def read_ki(self):
837 """
838 Read Ki in proprietary file.
839
840 Requires ADM1 access level
841 """
842 return self._scc.read_binary(self._EF['Ki'])
843
844
845 def update_ki(self, ki):
846 """
847 Set Ki in proprietary file.
848
849 Requires ADM1 access level
850 """
851 data, sw = self._scc.update_binary(self._EF['Ki'], ki)
852 return sw
853
854
855 def read_op_opc(self):
856 """
857 Read Ki in proprietary file.
858
859 Requires ADM1 access level
860 """
861 (ef, sw) = self._scc.read_binary(self._EF['OP/OPC'])
862 type = 'OP' if ef[0:2] == '00' else 'OPC'
863 return ((type, ef[2:]), sw)
864
865
866 def update_op(self, op):
867 """
868 Set OP in proprietary file.
869
870 Requires ADM1 access level
871 """
872 content = '00' + op
873 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
874 return sw
875
876
877 def update_opc(self, opc):
878 """
879 Set OPC in proprietary file.
880
881 Requires ADM1 access level
882 """
883 content = '01' + opc
884 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
885 return sw
886
887
888 def program(self, p):
889 # authenticate as ADM1
890 if not p['pin_adm']:
891 raise ValueError("Please provide a PIN-ADM as there is no default one")
892 sw = self.verify_adm(h2b(p['pin_adm']))
893 if sw != '9000':
894 raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
895
896 # TODO: Set operator name
897 if p.get('smsp') is not None:
898 sw = self.update_smsp(p['smsp'])
899 if sw != '9000':
900 print("Programming SMSP failed with code %s"%sw)
901 # This SIM doesn't support changing ICCID
902 if p.get('mcc') is not None and p.get('mnc') is not None:
903 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
904 if sw != '9000':
905 print("Programming MCC/MNC failed with code %s"%sw)
906 if p.get('imsi') is not None:
907 sw = self.update_imsi(p['imsi'])
908 if sw != '9000':
909 print("Programming IMSI failed with code %s"%sw)
910 if p.get('ki') is not None:
911 sw = self.update_ki(p['ki'])
912 if sw != '9000':
913 print("Programming Ki failed with code %s"%sw)
914 if p.get('opc') is not None:
915 sw = self.update_opc(p['opc'])
916 if sw != '9000':
917 print("Programming OPC failed with code %s"%sw)
918 if p.get('acc') is not None:
919 sw = self.update_acc(p['acc'])
920 if sw != '9000':
921 print("Programming ACC failed with code %s"%sw)
Jan Balke3e840672015-01-26 15:36:27 +0100922
Todd Neal9eeadfc2018-04-25 15:36:29 -0500923class OpenCellsSim(Card):
924 """
925 OpenCellsSim
926
927 """
928
Philipp Maier5a876312019-11-11 11:01:46 +0100929 name = 'OpenCells-SIM'
Todd Neal9eeadfc2018-04-25 15:36:29 -0500930
931 def __init__(self, ssc):
932 super(OpenCellsSim, self).__init__(ssc)
933 self._adm_chv_num = 0x0A
934
935
936 @classmethod
937 def autodetect(kls, scc):
938 try:
939 # Look for ATR
940 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"):
941 return kls(scc)
942 except:
943 return None
944 return None
945
946
947 def program(self, p):
948 if not p['pin_adm']:
949 raise ValueError("Please provide a PIN-ADM as there is no default one")
950 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
951
952 # select MF
953 r = self._scc.select_file(['3f00'])
954
955 # write EF.ICCID
956 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
957
958 r = self._scc.select_file(['7ff0'])
959
960 # set Ki in proprietary file
961 data, sw = self._scc.update_binary('FF02', p['ki'])
962
963 # set OPC in proprietary file
964 data, sw = self._scc.update_binary('FF01', p['opc'])
965
966 # select DF_GSM
967 r = self._scc.select_file(['7f20'])
968
969 # write EF.IMSI
970 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
971
herlesupreeth4a3580b2020-09-29 10:11:36 +0200972class WavemobileSim(UsimCard):
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200973 """
974 WavemobileSim
975
976 """
977
978 name = 'Wavemobile-SIM'
979
980 def __init__(self, ssc):
981 super(WavemobileSim, self).__init__(ssc)
982 self._adm_chv_num = 0x0A
983 self._scc.cla_byte = "00"
984 self._scc.sel_ctrl = "0004" #request an FCP
985
986 @classmethod
987 def autodetect(kls, scc):
988 try:
989 # Look for ATR
990 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"):
991 return kls(scc)
992 except:
993 return None
994 return None
995
996 def program(self, p):
997 if not p['pin_adm']:
998 raise ValueError("Please provide a PIN-ADM as there is no default one")
999 sw = self.verify_adm(h2b(p['pin_adm']))
1000 if sw != '9000':
1001 raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
1002
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001003 # EF.ICCID
1004 # TODO: Add programming of the ICCID
1005 if p.get('iccid'):
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001006 print("Warning: Programming of the ICCID is not implemented for this type of card.")
1007
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001008 # KI (Presumably a propritary file)
1009 # TODO: Add programming of KI
1010 if p.get('ki'):
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001011 print("Warning: Programming of the KI is not implemented for this type of card.")
1012
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001013 # OPc (Presumably a propritary file)
1014 # TODO: Add programming of OPc
1015 if p.get('opc'):
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001016 print("Warning: Programming of the OPc is not implemented for this type of card.")
1017
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001018 # EF.SMSP
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001019 if p.get('smsp'):
1020 sw = self.update_smsp(p['smsp'])
1021 if sw != '9000':
1022 print("Programming SMSP failed with code %s"%sw)
1023
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001024 # EF.IMSI
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001025 if p.get('imsi'):
1026 sw = self.update_imsi(p['imsi'])
1027 if sw != '9000':
1028 print("Programming IMSI failed with code %s"%sw)
1029
1030 # EF.ACC
1031 if p.get('acc'):
1032 sw = self.update_acc(p['acc'])
1033 if sw != '9000':
1034 print("Programming ACC failed with code %s"%sw)
1035
1036 # EF.PLMNsel
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001037 if p.get('mcc') and p.get('mnc'):
1038 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1039 if sw != '9000':
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001040 print("Programming PLMNsel failed with code %s"%sw)
1041
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001042 # EF.PLMNwAcT
1043 if p.get('mcc') and p.get('mnc'):
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001044 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1045 if sw != '9000':
1046 print("Programming PLMNwAcT failed with code %s"%sw)
1047
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001048 # EF.OPLMNwAcT
1049 if p.get('mcc') and p.get('mnc'):
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001050 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1051 if sw != '9000':
1052 print("Programming OPLMNwAcT failed with code %s"%sw)
1053
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001054 # EF.AD
1055 if p.get('mcc') and p.get('mnc'):
Philipp Maier6e507a72019-04-01 16:33:48 +02001056 sw = self.update_ad(p['mnc'])
1057 if sw != '9000':
1058 print("Programming AD failed with code %s"%sw)
1059
Denis 'GNUtoo' Carikli84d2cb32019-09-12 01:46:25 +02001060 return None
Philipp Maierc8ce82a2018-07-04 17:57:20 +02001061
Todd Neal9eeadfc2018-04-25 15:36:29 -05001062
Harald Welteca673942020-06-03 15:19:40 +02001063class SysmoISIMSJA2(UsimCard):
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001064 """
1065 sysmocom sysmoISIM-SJA2
1066 """
1067
1068 name = 'sysmoISIM-SJA2'
1069
1070 def __init__(self, ssc):
1071 super(SysmoISIMSJA2, self).__init__(ssc)
1072 self._scc.cla_byte = "00"
1073 self._scc.sel_ctrl = "0004" #request an FCP
1074
1075 @classmethod
1076 def autodetect(kls, scc):
1077 try:
1078 # Try card model #1
1079 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9"
1080 if scc.get_atr() == toBytes(atr):
1081 return kls(scc)
1082
1083 # Try card model #2
1084 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2"
1085 if scc.get_atr() == toBytes(atr):
1086 return kls(scc)
Philipp Maierb3e11ea2020-03-11 12:32:44 +01001087
1088 # Try card model #3
1089 atr = "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"
1090 if scc.get_atr() == toBytes(atr):
1091 return kls(scc)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001092 except:
1093 return None
1094 return None
1095
1096 def program(self, p):
1097 # authenticate as ADM using default key (written on the card..)
1098 if not p['pin_adm']:
1099 raise ValueError("Please provide a PIN-ADM as there is no default one")
1100 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
1101
1102 # This type of card does not allow to reprogram the ICCID.
1103 # Reprogramming the ICCID would mess up the card os software
1104 # license management, so the ICCID must be kept at its factory
1105 # setting!
1106 if p.get('iccid'):
1107 print("Warning: Programming of the ICCID is not implemented for this type of card.")
1108
1109 # select DF_GSM
1110 self._scc.select_file(['7f20'])
1111
1112 # write EF.IMSI
1113 if p.get('imsi'):
1114 self._scc.update_binary('6f07', enc_imsi(p['imsi']))
1115
1116 # EF.PLMNsel
1117 if p.get('mcc') and p.get('mnc'):
1118 sw = self.update_plmnsel(p['mcc'], p['mnc'])
1119 if sw != '9000':
1120 print("Programming PLMNsel failed with code %s"%sw)
1121
1122 # EF.PLMNwAcT
1123 if p.get('mcc') and p.get('mnc'):
1124 sw = self.update_plmn_act(p['mcc'], p['mnc'])
1125 if sw != '9000':
1126 print("Programming PLMNwAcT failed with code %s"%sw)
1127
1128 # EF.OPLMNwAcT
1129 if p.get('mcc') and p.get('mnc'):
1130 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
1131 if sw != '9000':
1132 print("Programming OPLMNwAcT failed with code %s"%sw)
1133
Harald Welte32f0d412020-05-05 17:35:57 +02001134 # EF.HPLMNwAcT
1135 if p.get('mcc') and p.get('mnc'):
1136 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
1137 if sw != '9000':
1138 print("Programming HPLMNwAcT failed with code %s"%sw)
1139
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001140 # EF.AD
1141 if p.get('mcc') and p.get('mnc'):
1142 sw = self.update_ad(p['mnc'])
1143 if sw != '9000':
1144 print("Programming AD failed with code %s"%sw)
1145
1146 # EF.SMSP
1147 if p.get('smsp'):
1148 r = self._scc.select_file(['3f00', '7f10'])
1149 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
1150
Supreeth Herle80164052020-03-23 12:06:29 +01001151 # Populate AIDs
1152 self.read_aids()
1153
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001154 # update EF-SIM_AUTH_KEY (and EF-USIM_AUTH_KEY_2G, which is
1155 # hard linked to EF-USIM_AUTH_KEY)
1156 self._scc.select_file(['3f00'])
1157 self._scc.select_file(['a515'])
1158 if p.get('ki'):
1159 self._scc.update_binary('6f20', p['ki'], 1)
1160 if p.get('opc'):
1161 self._scc.update_binary('6f20', p['opc'], 17)
1162
1163 # update EF-USIM_AUTH_KEY in ADF.ISIM
herlesupreeth1a13c442020-09-11 21:16:51 +02001164 if '9000' == self.select_adf_by_aid(adf="isim"):
Philipp Maierd9507862020-03-11 12:18:29 +01001165 if p.get('ki'):
1166 self._scc.update_binary('af20', p['ki'], 1)
1167 if p.get('opc'):
1168 self._scc.update_binary('af20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001169
herlesupreeth1a13c442020-09-11 21:16:51 +02001170 if '9000' == self.select_adf_by_aid():
Harald Welteca673942020-06-03 15:19:40 +02001171 # update EF-USIM_AUTH_KEY in ADF.USIM
Philipp Maierd9507862020-03-11 12:18:29 +01001172 if p.get('ki'):
1173 self._scc.update_binary('af20', p['ki'], 1)
1174 if p.get('opc'):
1175 self._scc.update_binary('af20', p['opc'], 17)
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001176
Harald Welteca673942020-06-03 15:19:40 +02001177 # update EF.EHPLMN in ADF.USIM
Harald Welte1e424202020-08-31 15:04:19 +02001178 if self.file_exists(EF_USIM_ADF_map['EHPLMN']):
Harald Welteca673942020-06-03 15:19:40 +02001179 if p.get('mcc') and p.get('mnc'):
1180 sw = self.update_ehplmn(p['mcc'], p['mnc'])
1181 if sw != '9000':
1182 print("Programming EHPLMN failed with code %s"%sw)
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001183
1184 # update EF.ePDGId in ADF.USIM
1185 if self.file_exists(EF_USIM_ADF_map['ePDGId']):
1186 if p.get('epdgid'):
herlesupreeth5d0a30c2020-09-29 09:44:24 +02001187 sw = self.update_epdgid(p['epdgid'])
Supreeth Herle8e0fccd2020-03-23 12:10:56 +01001188 if sw != '9000':
1189 print("Programming ePDGId failed with code %s"%sw)
1190
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001191 return
1192
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001193
Todd Neal9eeadfc2018-04-25 15:36:29 -05001194# In order for autodetection ...
Harald Weltee10394b2011-12-07 12:34:14 +01001195_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
Alexander Chemerise0d9d882018-01-10 14:18:32 +09001196 SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
Philipp Maier0ad5bcf2019-12-31 17:55:47 +01001197 FairwavesSIM, OpenCellsSim, WavemobileSim, SysmoISIMSJA2 ]
Alexander Chemeris8ad124a2018-01-10 14:17:55 +09001198
1199def card_autodetect(scc):
1200 for kls in _cards_classes:
1201 card = kls.autodetect(scc)
1202 if card is not None:
1203 card.reset()
1204 return card
1205 return None
Supreeth Herle4c306ab2020-03-18 11:38:00 +01001206
1207def card_detect(ctype, scc):
1208 # Detect type if needed
1209 card = None
1210 ctypes = dict([(kls.name, kls) for kls in _cards_classes])
1211
1212 if ctype in ("auto", "auto_once"):
1213 for kls in _cards_classes:
1214 card = kls.autodetect(scc)
1215 if card:
1216 print("Autodetected card type: %s" % card.name)
1217 card.reset()
1218 break
1219
1220 if card is None:
1221 print("Autodetection failed")
1222 return None
1223
1224 if ctype == "auto_once":
1225 ctype = card.name
1226
1227 elif ctype in ctypes:
1228 card = ctypes[ctype](scc)
1229
1230 else:
1231 raise ValueError("Unknown card type: %s" % ctype)
1232
1233 return card