blob: 3a25040812f4da40ec03934665bf25d2ba03db9d [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
27from pySim.utils import *
Alexander Chemeris8ad124a2018-01-10 14:17:55 +090028from smartcard.util import toBytes
Sylvain Munaut76504e02010-12-07 00:24:32 +010029
30class Card(object):
31
32 def __init__(self, scc):
33 self._scc = scc
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030034 self._adm_chv_num = 4
Sylvain Munaut76504e02010-12-07 00:24:32 +010035
Sylvain Munaut76504e02010-12-07 00:24:32 +010036 def reset(self):
37 self._scc.reset_card()
38
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030039 def verify_adm(self, key):
40 '''
41 Authenticate with ADM key
42 '''
43 (res, sw) = self._scc.verify_chv(self._adm_chv_num, key)
44 return sw
45
46 def read_iccid(self):
47 (res, sw) = self._scc.read_binary(EF['ICCID'])
48 if sw == '9000':
49 return (dec_iccid(res), sw)
50 else:
51 return (None, sw)
52
53 def read_imsi(self):
54 (res, sw) = self._scc.read_binary(EF['IMSI'])
55 if sw == '9000':
56 return (dec_imsi(res), sw)
57 else:
58 return (None, sw)
59
60 def update_imsi(self, imsi):
61 data, sw = self._scc.update_binary(EF['IMSI'], enc_imsi(imsi))
62 return sw
63
64 def update_acc(self, acc):
65 data, sw = self._scc.update_binary(EF['ACC'], lpad(acc, 4))
66 return sw
67
68 def update_hplmn_act(self, mcc, mnc, access_tech='FFFF'):
69 """
70 Update Home PLMN with access technology bit-field
71
72 See Section "10.3.37 EFHPLMNwAcT (HPLMN Selector with Access Technology)"
73 in ETSI TS 151 011 for the details of the access_tech field coding.
74 Some common values:
75 access_tech = '0080' # Only GSM is selected
76 access_tech = 'FFFF' # All technologues selected, even Reserved for Future Use ones
77 """
78 # get size and write EF.HPLMNwAcT
79 r = self._scc.select_file(EF['HPLMNwAcT'])
80 size = int(r[-1][4:8], 16)
81 hplmn = enc_plmn(mcc, mnc)
82 content = hplmn + access_tech
83 data, sw = self._scc.update_binary(EF['HPLMNwAcT'], content + 'ffffff0000' * (size/5-1))
84 return sw
85
Philipp Maierc8ce82a2018-07-04 17:57:20 +020086 def update_oplmn_act(self, mcc, mnc, access_tech='FFFF'):
87 """
88 See note in update_hplmn_act()
89 """
90 # get size and write EF.OPLMNwAcT
91 data = self._scc.read_binary(EF['OPLMNwAcT'], length=None, offset=0)
92 size = len(data[0])/2
93 hplmn = enc_plmn(mcc, mnc)
94 content = hplmn + access_tech
95 data, sw = self._scc.update_binary(EF['OPLMNwAcT'], content + 'ffffff0000' * (size/5-1))
96 return sw
97
98 def update_plmn_act(self, mcc, mnc, access_tech='FFFF'):
99 """
100 See note in update_hplmn_act()
101 """
102 # get size and write EF.PLMNwAcT
103 data = self._scc.read_binary(EF['PLMNwAcT'], length=None, offset=0)
104 size = len(data[0])/2
105 hplmn = enc_plmn(mcc, mnc)
106 content = hplmn + access_tech
107 data, sw = self._scc.update_binary(EF['PLMNwAcT'], content + 'ffffff0000' * (size/5-1))
108 return sw
109
Philipp Maier5bf42602018-07-11 23:23:40 +0200110 def update_plmnsel(self, mcc, mnc):
111 data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
112 size = len(data[0])/2
113 hplmn = enc_plmn(mcc, mnc)
Philipp Maieraf9ae8b2018-07-13 11:15:49 +0200114 data, sw = self._scc.update_binary(EF['PLMNsel'], hplmn + 'ff' * (size-3))
115 return sw
Philipp Maier5bf42602018-07-11 23:23:40 +0200116
Alexander Chemeriseb6807d2017-07-18 17:04:38 +0300117 def update_smsp(self, smsp):
118 data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 84))
119 return sw
120
121 def read_spn(self):
122 (spn, sw) = self._scc.read_binary(EF['SPN'])
123 if sw == '9000':
124 return (dec_spn(spn), sw)
125 else:
126 return (None, sw)
127
128 def update_spn(self, name, hplmn_disp=False, oplmn_disp=False):
129 content = enc_spn(name, hplmn_disp, oplmn_disp)
130 data, sw = self._scc.update_binary(EF['SPN'], rpad(content, 32))
131 return sw
132
Sylvain Munaut76504e02010-12-07 00:24:32 +0100133
134class _MagicSimBase(Card):
135 """
136 Theses cards uses several record based EFs to store the provider infos,
137 each possible provider uses a specific record number in each EF. The
138 indexes used are ( where N is the number of providers supported ) :
139 - [2 .. N+1] for the operator name
140 - [1 .. N] for the programable EFs
141
142 * 3f00/7f4d/8f0c : Operator Name
143
144 bytes 0-15 : provider name, padded with 0xff
145 byte 16 : length of the provider name
146 byte 17 : 01 for valid records, 00 otherwise
147
148 * 3f00/7f4d/8f0d : Programmable Binary EFs
149
150 * 3f00/7f4d/8f0e : Programmable Record EFs
151
152 """
153
154 @classmethod
155 def autodetect(kls, scc):
156 try:
157 for p, l, t in kls._files.values():
158 if not t:
159 continue
160 if scc.record_size(['3f00', '7f4d', p]) != l:
161 return None
162 except:
163 return None
164
165 return kls(scc)
166
167 def _get_count(self):
168 """
169 Selects the file and returns the total number of entries
170 and entry size
171 """
172 f = self._files['name']
173
174 r = self._scc.select_file(['3f00', '7f4d', f[0]])
175 rec_len = int(r[-1][28:30], 16)
176 tlen = int(r[-1][4:8],16)
177 rec_cnt = (tlen / rec_len) - 1;
178
179 if (rec_cnt < 1) or (rec_len != f[1]):
180 raise RuntimeError('Bad card type')
181
182 return rec_cnt
183
184 def program(self, p):
185 # Go to dir
186 self._scc.select_file(['3f00', '7f4d'])
187
188 # Home PLMN in PLMN_Sel format
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400189 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100190
191 # Operator name ( 3f00/7f4d/8f0c )
192 self._scc.update_record(self._files['name'][0], 2,
193 rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01'
194 )
195
196 # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
197 v = ''
198
199 # inline Ki
200 if self._ki_file is None:
201 v += p['ki']
202
203 # ICCID
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400204 v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100205
206 # IMSI
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400207 v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100208
209 # Ki
210 if self._ki_file:
211 v += self._ki_file + '10' + p['ki']
212
213 # PLMN_Sel
214 v+= '6f30' + '18' + rpad(hplmn, 36)
215
Alexander Chemeris21885242013-07-02 16:56:55 +0400216 # ACC
217 # This doesn't work with "fake" SuperSIM cards,
218 # but will hopefully work with real SuperSIMs.
219 if p.get('acc') is not None:
220 v+= '6f78' + '02' + lpad(p['acc'], 4)
221
Sylvain Munaut76504e02010-12-07 00:24:32 +0100222 self._scc.update_record(self._files['b_ef'][0], 1,
223 rpad(v, self._files['b_ef'][1]*2)
224 )
225
226 # SMSP ( 3f00/7f4d/8f0e )
227 # FIXME
228
229 # Write PLMN_Sel forcefully as well
230 r = self._scc.select_file(['3f00', '7f20', '6f30'])
231 tl = int(r[-1][4:8], 16)
232
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400233 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100234 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
235
236 def erase(self):
237 # Dummy
238 df = {}
239 for k, v in self._files.iteritems():
240 ofs = 1
241 fv = v[1] * 'ff'
242 if k == 'name':
243 ofs = 2
244 fv = fv[0:-4] + '0000'
245 df[v[0]] = (fv, ofs)
246
247 # Write
248 for n in range(0,self._get_count()):
249 for k, (msg, ofs) in df.iteritems():
250 self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
251
252
253class SuperSim(_MagicSimBase):
254
255 name = 'supersim'
256
257 _files = {
258 'name' : ('8f0c', 18, True),
259 'b_ef' : ('8f0d', 74, True),
260 'r_ef' : ('8f0e', 50, True),
261 }
262
263 _ki_file = None
264
265
266class MagicSim(_MagicSimBase):
267
268 name = 'magicsim'
269
270 _files = {
271 'name' : ('8f0c', 18, True),
272 'b_ef' : ('8f0d', 130, True),
273 'r_ef' : ('8f0e', 102, False),
274 }
275
276 _ki_file = '6f1b'
277
278
279class FakeMagicSim(Card):
280 """
281 Theses cards have a record based EF 3f00/000c that contains the provider
282 informations. See the program method for its format. The records go from
283 1 to N.
284 """
285
286 name = 'fakemagicsim'
287
288 @classmethod
289 def autodetect(kls, scc):
290 try:
291 if scc.record_size(['3f00', '000c']) != 0x5a:
292 return None
293 except:
294 return None
295
296 return kls(scc)
297
298 def _get_infos(self):
299 """
300 Selects the file and returns the total number of entries
301 and entry size
302 """
303
304 r = self._scc.select_file(['3f00', '000c'])
305 rec_len = int(r[-1][28:30], 16)
306 tlen = int(r[-1][4:8],16)
307 rec_cnt = (tlen / rec_len) - 1;
308
309 if (rec_cnt < 1) or (rec_len != 0x5a):
310 raise RuntimeError('Bad card type')
311
312 return rec_cnt, rec_len
313
314 def program(self, p):
315 # Home PLMN
316 r = self._scc.select_file(['3f00', '7f20', '6f30'])
317 tl = int(r[-1][4:8], 16)
318
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400319 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100320 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
321
322 # Get total number of entries and entry size
323 rec_cnt, rec_len = self._get_infos()
324
325 # Set first entry
326 entry = (
327 '81' + # 1b Status: Valid & Active
328 rpad(b2h(p['name'][0:14]), 28) + # 14b Entry Name
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400329 enc_iccid(p['iccid']) + # 10b ICCID
330 enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
Sylvain Munaut76504e02010-12-07 00:24:32 +0100331 p['ki'] + # 16b Ki
Sylvain Munaut8ca49e92011-12-10 09:57:50 +0100332 lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100333 )
334 self._scc.update_record('000c', 1, entry)
335
336 def erase(self):
337 # Get total number of entries and entry size
338 rec_cnt, rec_len = self._get_infos()
339
340 # Erase all entries
341 entry = 'ff' * rec_len
342 for i in range(0, rec_cnt):
343 self._scc.update_record('000c', 1+i, entry)
344
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200345
Harald Welte3156d902011-03-22 21:48:19 +0100346class GrcardSim(Card):
347 """
348 Greencard (grcard.cn) HZCOS GSM SIM
349 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
350 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
351 """
352
353 name = 'grcardsim'
354
355 @classmethod
356 def autodetect(kls, scc):
357 return None
358
359 def program(self, p):
360 # We don't really know yet what ADM PIN 4 is about
361 #self._scc.verify_chv(4, h2b("4444444444444444"))
362
363 # Authenticate using ADM PIN 5
Jan Balkec3ebd332015-01-26 12:22:55 +0100364 if p['pin_adm']:
Philipp Maiera3de5a32018-08-23 10:27:04 +0200365 pin = h2b(p['pin_adm'])
Jan Balkec3ebd332015-01-26 12:22:55 +0100366 else:
367 pin = h2b("4444444444444444")
368 self._scc.verify_chv(5, pin)
Harald Welte3156d902011-03-22 21:48:19 +0100369
370 # EF.ICCID
371 r = self._scc.select_file(['3f00', '2fe2'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400372 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100373
374 # EF.IMSI
375 r = self._scc.select_file(['3f00', '7f20', '6f07'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400376 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100377
378 # EF.ACC
Alexander Chemeris21885242013-07-02 16:56:55 +0400379 if p.get('acc') is not None:
380 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100381
382 # EF.SMSP
383 r = self._scc.select_file(['3f00', '7f10', '6f42'])
Sylvain Munaut8ca49e92011-12-10 09:57:50 +0100384 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100385
386 # Set the Ki using proprietary command
387 pdu = '80d4020010' + p['ki']
388 data, sw = self._scc._tp.send_apdu(pdu)
389
390 # EF.HPLMN
391 r = self._scc.select_file(['3f00', '7f20', '6f30'])
392 size = int(r[-1][4:8], 16)
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400393 hplmn = enc_plmn(p['mcc'], p['mnc'])
Harald Welte3156d902011-03-22 21:48:19 +0100394 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
395
396 # EF.SPN (Service Provider Name)
397 r = self._scc.select_file(['3f00', '7f20', '6f30'])
398 size = int(r[-1][4:8], 16)
399 # FIXME
400
401 # FIXME: EF.MSISDN
402
403 def erase(self):
404 return
Sylvain Munaut76504e02010-12-07 00:24:32 +0100405
Harald Weltee10394b2011-12-07 12:34:14 +0100406class SysmoSIMgr1(GrcardSim):
407 """
408 sysmocom sysmoSIM-GR1
409 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
410 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
411 """
412 name = 'sysmosim-gr1'
413
Philipp Maier087feff2018-08-23 09:41:36 +0200414 @classmethod
415 def autodetect(kls, scc):
416 try:
417 # Look for ATR
418 if scc.get_atr() == toBytes("3B 99 18 00 11 88 22 33 44 55 66 77 60"):
419 return kls(scc)
420 except:
421 return None
422 return None
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200423
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100424class SysmoUSIMgr1(Card):
425 """
426 sysmocom sysmoUSIM-GR1
427 """
428 name = 'sysmoUSIM-GR1'
429
430 @classmethod
431 def autodetect(kls, scc):
432 # TODO: Access the ATR
433 return None
434
435 def program(self, p):
436 # TODO: check if verify_chv could be used or what it needs
437 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
438 # Unlock the card..
439 data, sw = self._scc._tp.send_apdu_checksw("0020000A083332323133323332")
440
441 # TODO: move into SimCardCommands
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100442 par = ( p['ki'] + # 16b K
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400443 p['opc'] + # 32b OPC
444 enc_iccid(p['iccid']) + # 10b ICCID
445 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100446 )
447 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
448
449 def erase(self):
450 return
451
Sylvain Munaut053c8952013-07-02 15:12:32 +0200452
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100453class SysmoSIMgr2(Card):
454 """
455 sysmocom sysmoSIM-GR2
456 """
457
458 name = 'sysmoSIM-GR2'
459
460 @classmethod
461 def autodetect(kls, scc):
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900462 try:
463 # Look for ATR
464 if scc.get_atr() == toBytes("3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68"):
465 return kls(scc)
466 except:
467 return None
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100468 return None
469
470 def program(self, p):
471
472 # select MF
473 r = self._scc.select_file(['3f00'])
474
475 # authenticate as SUPER ADM using default key
476 self._scc.verify_chv(0x0b, h2b("3838383838383838"))
477
478 # set ADM pin using proprietary command
479 # INS: D4
480 # P1: 3A for PIN, 3B for PUK
481 # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
482 # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
Jan Balkec3ebd332015-01-26 12:22:55 +0100483 if p['pin_adm']:
484 pin = p['pin_adm']
485 else:
486 pin = h2b("4444444444444444")
487
488 pdu = 'A0D43A0508' + b2h(pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100489 data, sw = self._scc._tp.send_apdu(pdu)
490
491 # authenticate as ADM (enough to write file, and can set PINs)
Jan Balkec3ebd332015-01-26 12:22:55 +0100492
493 self._scc.verify_chv(0x05, pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100494
495 # write EF.ICCID
496 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
497
498 # select DF_GSM
499 r = self._scc.select_file(['7f20'])
500
501 # write EF.IMSI
502 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
503
504 # write EF.ACC
505 if p.get('acc') is not None:
506 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
507
508 # get size and write EF.HPLMN
509 r = self._scc.select_file(['6f30'])
510 size = int(r[-1][4:8], 16)
511 hplmn = enc_plmn(p['mcc'], p['mnc'])
512 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
513
514 # set COMP128 version 0 in proprietary file
515 data, sw = self._scc.update_binary('0001', '001000')
516
517 # set Ki in proprietary file
518 data, sw = self._scc.update_binary('0001', p['ki'], 3)
519
520 # select DF_TELECOM
521 r = self._scc.select_file(['3f00', '7f10'])
522
523 # write EF.SMSP
524 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
525
526 def erase(self):
527 return
528
Jan Balke3e840672015-01-26 15:36:27 +0100529class SysmoUSIMSJS1(Card):
530 """
531 sysmocom sysmoUSIM-SJS1
532 """
533
534 name = 'sysmoUSIM-SJS1'
535
536 def __init__(self, ssc):
537 super(SysmoUSIMSJS1, self).__init__(ssc)
538 self._scc.cla_byte = "00"
Philipp Maier41460862017-03-21 12:05:30 +0100539 self._scc.sel_ctrl = "000C"
Jan Balke3e840672015-01-26 15:36:27 +0100540
541 @classmethod
542 def autodetect(kls, scc):
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900543 try:
544 # Look for ATR
545 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"):
546 return kls(scc)
547 except:
548 return None
Jan Balke3e840672015-01-26 15:36:27 +0100549 return None
550
551 def program(self, p):
552
Philipp Maiere9604882017-03-21 17:24:31 +0100553 # authenticate as ADM using default key (written on the card..)
554 if not p['pin_adm']:
555 raise ValueError("Please provide a PIN-ADM as there is no default one")
556 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
Jan Balke3e840672015-01-26 15:36:27 +0100557
558 # select MF
559 r = self._scc.select_file(['3f00'])
560
Philipp Maiere9604882017-03-21 17:24:31 +0100561 # write EF.ICCID
562 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
563
Jan Balke3e840672015-01-26 15:36:27 +0100564 # select DF_GSM
565 r = self._scc.select_file(['7f20'])
566
Jan Balke3e840672015-01-26 15:36:27 +0100567 # set Ki in proprietary file
568 data, sw = self._scc.update_binary('00FF', p['ki'])
569
Philipp Maier1be35bf2018-07-13 11:29:03 +0200570 # set OPc in proprietary file
Jan Balke3e840672015-01-26 15:36:27 +0100571 content = "01" + p['opc']
572 data, sw = self._scc.update_binary('00F7', content)
573
574
575 # write EF.IMSI
576 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
577
Daniel Willmann1d087ef2017-08-31 10:08:45 +0200578 # EF.SMSP
579 r = self._scc.select_file(['3f00', '7f10'])
580 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
Jan Balke3e840672015-01-26 15:36:27 +0100581
Alexander Chemerise0d9d882018-01-10 14:18:32 +0900582 def erase(self):
583 return
584
585
586class FairwavesSIM(Card):
587 """
588 FairwavesSIM
589
590 The SIM card is operating according to the standard.
591 For Ki/OP/OPC programming the following files are additionally open for writing:
592 3F00/7F20/FF01 – OP/OPC:
593 byte 1 = 0x01, bytes 2-17: OPC;
594 byte 1 = 0x00, bytes 2-17: OP;
595 3F00/7F20/FF02: Ki
596 """
597
598 name = 'Fairwaves SIM'
599 # Propriatary files
600 _EF_num = {
601 'Ki': 'FF02',
602 'OP/OPC': 'FF01',
603 }
604 _EF = {
605 'Ki': DF['GSM']+[_EF_num['Ki']],
606 'OP/OPC': DF['GSM']+[_EF_num['OP/OPC']],
607 }
608
609 def __init__(self, ssc):
610 super(FairwavesSIM, self).__init__(ssc)
611 self._adm_chv_num = 0x11
612 self._adm2_chv_num = 0x12
613
614
615 @classmethod
616 def autodetect(kls, scc):
617 try:
618 # Look for ATR
619 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"):
620 return kls(scc)
621 except:
622 return None
623 return None
624
625
626 def verify_adm2(self, key):
627 '''
628 Authenticate with ADM2 key.
629
630 Fairwaves SIM cards support hierarchical key structure and ADM2 key
631 is a key which has access to proprietary files (Ki and OP/OPC).
632 That said, ADM key inherits permissions of ADM2 key and thus we rarely
633 need ADM2 key per se.
634 '''
635 (res, sw) = self._scc.verify_chv(self._adm2_chv_num, key)
636 return sw
637
638
639 def read_ki(self):
640 """
641 Read Ki in proprietary file.
642
643 Requires ADM1 access level
644 """
645 return self._scc.read_binary(self._EF['Ki'])
646
647
648 def update_ki(self, ki):
649 """
650 Set Ki in proprietary file.
651
652 Requires ADM1 access level
653 """
654 data, sw = self._scc.update_binary(self._EF['Ki'], ki)
655 return sw
656
657
658 def read_op_opc(self):
659 """
660 Read Ki in proprietary file.
661
662 Requires ADM1 access level
663 """
664 (ef, sw) = self._scc.read_binary(self._EF['OP/OPC'])
665 type = 'OP' if ef[0:2] == '00' else 'OPC'
666 return ((type, ef[2:]), sw)
667
668
669 def update_op(self, op):
670 """
671 Set OP in proprietary file.
672
673 Requires ADM1 access level
674 """
675 content = '00' + op
676 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
677 return sw
678
679
680 def update_opc(self, opc):
681 """
682 Set OPC in proprietary file.
683
684 Requires ADM1 access level
685 """
686 content = '01' + opc
687 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
688 return sw
689
690
691 def program(self, p):
692 # authenticate as ADM1
693 if not p['pin_adm']:
694 raise ValueError("Please provide a PIN-ADM as there is no default one")
695 sw = self.verify_adm(h2b(p['pin_adm']))
696 if sw != '9000':
697 raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
698
699 # TODO: Set operator name
700 if p.get('smsp') is not None:
701 sw = self.update_smsp(p['smsp'])
702 if sw != '9000':
703 print("Programming SMSP failed with code %s"%sw)
704 # This SIM doesn't support changing ICCID
705 if p.get('mcc') is not None and p.get('mnc') is not None:
706 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
707 if sw != '9000':
708 print("Programming MCC/MNC failed with code %s"%sw)
709 if p.get('imsi') is not None:
710 sw = self.update_imsi(p['imsi'])
711 if sw != '9000':
712 print("Programming IMSI failed with code %s"%sw)
713 if p.get('ki') is not None:
714 sw = self.update_ki(p['ki'])
715 if sw != '9000':
716 print("Programming Ki failed with code %s"%sw)
717 if p.get('opc') is not None:
718 sw = self.update_opc(p['opc'])
719 if sw != '9000':
720 print("Programming OPC failed with code %s"%sw)
721 if p.get('acc') is not None:
722 sw = self.update_acc(p['acc'])
723 if sw != '9000':
724 print("Programming ACC failed with code %s"%sw)
Jan Balke3e840672015-01-26 15:36:27 +0100725
726 def erase(self):
727 return
728
729
Todd Neal9eeadfc2018-04-25 15:36:29 -0500730class OpenCellsSim(Card):
731 """
732 OpenCellsSim
733
734 """
735
736 name = 'OpenCells SIM'
737
738 def __init__(self, ssc):
739 super(OpenCellsSim, self).__init__(ssc)
740 self._adm_chv_num = 0x0A
741
742
743 @classmethod
744 def autodetect(kls, scc):
745 try:
746 # Look for ATR
747 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"):
748 return kls(scc)
749 except:
750 return None
751 return None
752
753
754 def program(self, p):
755 if not p['pin_adm']:
756 raise ValueError("Please provide a PIN-ADM as there is no default one")
757 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
758
759 # select MF
760 r = self._scc.select_file(['3f00'])
761
762 # write EF.ICCID
763 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
764
765 r = self._scc.select_file(['7ff0'])
766
767 # set Ki in proprietary file
768 data, sw = self._scc.update_binary('FF02', p['ki'])
769
770 # set OPC in proprietary file
771 data, sw = self._scc.update_binary('FF01', p['opc'])
772
773 # select DF_GSM
774 r = self._scc.select_file(['7f20'])
775
776 # write EF.IMSI
777 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
778
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200779class WavemobileSim(Card):
780 """
781 WavemobileSim
782
783 """
784
785 name = 'Wavemobile-SIM'
786
787 def __init__(self, ssc):
788 super(WavemobileSim, self).__init__(ssc)
789 self._adm_chv_num = 0x0A
790 self._scc.cla_byte = "00"
791 self._scc.sel_ctrl = "0004" #request an FCP
792
793 @classmethod
794 def autodetect(kls, scc):
795 try:
796 # Look for ATR
797 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"):
798 return kls(scc)
799 except:
800 return None
801 return None
802
803 def program(self, p):
804 if not p['pin_adm']:
805 raise ValueError("Please provide a PIN-ADM as there is no default one")
806 sw = self.verify_adm(h2b(p['pin_adm']))
807 if sw != '9000':
808 raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
809
810 # EF.ICCID
811 # TODO: Add programming of the ICCID
812 if p.get('iccid'):
813 print("Warning: Programming of the ICCID is not implemented for this type of card.")
814
815 # KI (Presumably a propritary file)
816 # TODO: Add programming of KI
817 if p.get('ki'):
818 print("Warning: Programming of the KI is not implemented for this type of card.")
819
820 # OPc (Presumably a propritary file)
821 # TODO: Add programming of OPc
822 if p.get('opc'):
823 print("Warning: Programming of the OPc is not implemented for this type of card.")
824
825 # EF.SMSP
826 if p.get('smsp'):
827 sw = self.update_smsp(p['smsp'])
828 if sw != '9000':
829 print("Programming SMSP failed with code %s"%sw)
830
831 # EF.IMSI
832 if p.get('imsi'):
833 sw = self.update_imsi(p['imsi'])
834 if sw != '9000':
835 print("Programming IMSI failed with code %s"%sw)
836
837 # EF.ACC
838 if p.get('acc'):
839 sw = self.update_acc(p['acc'])
840 if sw != '9000':
841 print("Programming ACC failed with code %s"%sw)
842
843 # EF.PLMNsel
844 if p.get('mcc') and p.get('mnc'):
845 sw = self.update_plmnsel(p['mcc'], p['mnc'])
846 if sw != '9000':
847 print("Programming PLMNsel failed with code %s"%sw)
848
849 # EF.PLMNwAcT
850 if p.get('mcc') and p.get('mnc'):
851 sw = self.update_plmn_act(p['mcc'], p['mnc'])
852 if sw != '9000':
853 print("Programming PLMNwAcT failed with code %s"%sw)
854
855 # EF.OPLMNwAcT
856 if p.get('mcc') and p.get('mnc'):
857 sw = self.update_oplmn_act(p['mcc'], p['mnc'])
858 if sw != '9000':
859 print("Programming OPLMNwAcT failed with code %s"%sw)
860
861 return None
862
863 def erase(self):
864 return
865
Todd Neal9eeadfc2018-04-25 15:36:29 -0500866
867# In order for autodetection ...
Harald Weltee10394b2011-12-07 12:34:14 +0100868_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
Alexander Chemerise0d9d882018-01-10 14:18:32 +0900869 SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
Philipp Maierc8ce82a2018-07-04 17:57:20 +0200870 FairwavesSIM, OpenCellsSim, WavemobileSim ]
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900871
872def card_autodetect(scc):
873 for kls in _cards_classes:
874 card = kls.autodetect(scc)
875 if card is not None:
876 card.reset()
877 return card
878 return None