blob: 9be04ff98be7806118ea5626f835a2b5b8053ef6 [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 Maier5bf42602018-07-11 23:23:40 +020086 def update_plmnsel(self, mcc, mnc):
87 data = self._scc.read_binary(EF['PLMNsel'], length=None, offset=0)
88 size = len(data[0])/2
89 hplmn = enc_plmn(mcc, mnc)
90 self._scc.update_binary(EF['PLMNsel'], hplmn + 'ff' * (size-3))
91
Alexander Chemeriseb6807d2017-07-18 17:04:38 +030092 def update_smsp(self, smsp):
93 data, sw = self._scc.update_record(EF['SMSP'], 1, rpad(smsp, 84))
94 return sw
95
96 def read_spn(self):
97 (spn, sw) = self._scc.read_binary(EF['SPN'])
98 if sw == '9000':
99 return (dec_spn(spn), sw)
100 else:
101 return (None, sw)
102
103 def update_spn(self, name, hplmn_disp=False, oplmn_disp=False):
104 content = enc_spn(name, hplmn_disp, oplmn_disp)
105 data, sw = self._scc.update_binary(EF['SPN'], rpad(content, 32))
106 return sw
107
Sylvain Munaut76504e02010-12-07 00:24:32 +0100108
109class _MagicSimBase(Card):
110 """
111 Theses cards uses several record based EFs to store the provider infos,
112 each possible provider uses a specific record number in each EF. The
113 indexes used are ( where N is the number of providers supported ) :
114 - [2 .. N+1] for the operator name
115 - [1 .. N] for the programable EFs
116
117 * 3f00/7f4d/8f0c : Operator Name
118
119 bytes 0-15 : provider name, padded with 0xff
120 byte 16 : length of the provider name
121 byte 17 : 01 for valid records, 00 otherwise
122
123 * 3f00/7f4d/8f0d : Programmable Binary EFs
124
125 * 3f00/7f4d/8f0e : Programmable Record EFs
126
127 """
128
129 @classmethod
130 def autodetect(kls, scc):
131 try:
132 for p, l, t in kls._files.values():
133 if not t:
134 continue
135 if scc.record_size(['3f00', '7f4d', p]) != l:
136 return None
137 except:
138 return None
139
140 return kls(scc)
141
142 def _get_count(self):
143 """
144 Selects the file and returns the total number of entries
145 and entry size
146 """
147 f = self._files['name']
148
149 r = self._scc.select_file(['3f00', '7f4d', f[0]])
150 rec_len = int(r[-1][28:30], 16)
151 tlen = int(r[-1][4:8],16)
152 rec_cnt = (tlen / rec_len) - 1;
153
154 if (rec_cnt < 1) or (rec_len != f[1]):
155 raise RuntimeError('Bad card type')
156
157 return rec_cnt
158
159 def program(self, p):
160 # Go to dir
161 self._scc.select_file(['3f00', '7f4d'])
162
163 # Home PLMN in PLMN_Sel format
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400164 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100165
166 # Operator name ( 3f00/7f4d/8f0c )
167 self._scc.update_record(self._files['name'][0], 2,
168 rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01'
169 )
170
171 # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
172 v = ''
173
174 # inline Ki
175 if self._ki_file is None:
176 v += p['ki']
177
178 # ICCID
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400179 v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100180
181 # IMSI
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400182 v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100183
184 # Ki
185 if self._ki_file:
186 v += self._ki_file + '10' + p['ki']
187
188 # PLMN_Sel
189 v+= '6f30' + '18' + rpad(hplmn, 36)
190
Alexander Chemeris21885242013-07-02 16:56:55 +0400191 # ACC
192 # This doesn't work with "fake" SuperSIM cards,
193 # but will hopefully work with real SuperSIMs.
194 if p.get('acc') is not None:
195 v+= '6f78' + '02' + lpad(p['acc'], 4)
196
Sylvain Munaut76504e02010-12-07 00:24:32 +0100197 self._scc.update_record(self._files['b_ef'][0], 1,
198 rpad(v, self._files['b_ef'][1]*2)
199 )
200
201 # SMSP ( 3f00/7f4d/8f0e )
202 # FIXME
203
204 # Write PLMN_Sel forcefully as well
205 r = self._scc.select_file(['3f00', '7f20', '6f30'])
206 tl = int(r[-1][4:8], 16)
207
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400208 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100209 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
210
211 def erase(self):
212 # Dummy
213 df = {}
214 for k, v in self._files.iteritems():
215 ofs = 1
216 fv = v[1] * 'ff'
217 if k == 'name':
218 ofs = 2
219 fv = fv[0:-4] + '0000'
220 df[v[0]] = (fv, ofs)
221
222 # Write
223 for n in range(0,self._get_count()):
224 for k, (msg, ofs) in df.iteritems():
225 self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
226
227
228class SuperSim(_MagicSimBase):
229
230 name = 'supersim'
231
232 _files = {
233 'name' : ('8f0c', 18, True),
234 'b_ef' : ('8f0d', 74, True),
235 'r_ef' : ('8f0e', 50, True),
236 }
237
238 _ki_file = None
239
240
241class MagicSim(_MagicSimBase):
242
243 name = 'magicsim'
244
245 _files = {
246 'name' : ('8f0c', 18, True),
247 'b_ef' : ('8f0d', 130, True),
248 'r_ef' : ('8f0e', 102, False),
249 }
250
251 _ki_file = '6f1b'
252
253
254class FakeMagicSim(Card):
255 """
256 Theses cards have a record based EF 3f00/000c that contains the provider
257 informations. See the program method for its format. The records go from
258 1 to N.
259 """
260
261 name = 'fakemagicsim'
262
263 @classmethod
264 def autodetect(kls, scc):
265 try:
266 if scc.record_size(['3f00', '000c']) != 0x5a:
267 return None
268 except:
269 return None
270
271 return kls(scc)
272
273 def _get_infos(self):
274 """
275 Selects the file and returns the total number of entries
276 and entry size
277 """
278
279 r = self._scc.select_file(['3f00', '000c'])
280 rec_len = int(r[-1][28:30], 16)
281 tlen = int(r[-1][4:8],16)
282 rec_cnt = (tlen / rec_len) - 1;
283
284 if (rec_cnt < 1) or (rec_len != 0x5a):
285 raise RuntimeError('Bad card type')
286
287 return rec_cnt, rec_len
288
289 def program(self, p):
290 # Home PLMN
291 r = self._scc.select_file(['3f00', '7f20', '6f30'])
292 tl = int(r[-1][4:8], 16)
293
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400294 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100295 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
296
297 # Get total number of entries and entry size
298 rec_cnt, rec_len = self._get_infos()
299
300 # Set first entry
301 entry = (
302 '81' + # 1b Status: Valid & Active
303 rpad(b2h(p['name'][0:14]), 28) + # 14b Entry Name
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400304 enc_iccid(p['iccid']) + # 10b ICCID
305 enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
Sylvain Munaut76504e02010-12-07 00:24:32 +0100306 p['ki'] + # 16b Ki
Sylvain Munaut8ca49e92011-12-10 09:57:50 +0100307 lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100308 )
309 self._scc.update_record('000c', 1, entry)
310
311 def erase(self):
312 # Get total number of entries and entry size
313 rec_cnt, rec_len = self._get_infos()
314
315 # Erase all entries
316 entry = 'ff' * rec_len
317 for i in range(0, rec_cnt):
318 self._scc.update_record('000c', 1+i, entry)
319
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200320
Harald Welte3156d902011-03-22 21:48:19 +0100321class GrcardSim(Card):
322 """
323 Greencard (grcard.cn) HZCOS GSM SIM
324 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
325 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
326 """
327
328 name = 'grcardsim'
329
330 @classmethod
331 def autodetect(kls, scc):
332 return None
333
334 def program(self, p):
335 # We don't really know yet what ADM PIN 4 is about
336 #self._scc.verify_chv(4, h2b("4444444444444444"))
337
338 # Authenticate using ADM PIN 5
Jan Balkec3ebd332015-01-26 12:22:55 +0100339 if p['pin_adm']:
340 pin = p['pin_adm']
341 else:
342 pin = h2b("4444444444444444")
343 self._scc.verify_chv(5, pin)
Harald Welte3156d902011-03-22 21:48:19 +0100344
345 # EF.ICCID
346 r = self._scc.select_file(['3f00', '2fe2'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400347 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100348
349 # EF.IMSI
350 r = self._scc.select_file(['3f00', '7f20', '6f07'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400351 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100352
353 # EF.ACC
Alexander Chemeris21885242013-07-02 16:56:55 +0400354 if p.get('acc') is not None:
355 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100356
357 # EF.SMSP
358 r = self._scc.select_file(['3f00', '7f10', '6f42'])
Sylvain Munaut8ca49e92011-12-10 09:57:50 +0100359 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100360
361 # Set the Ki using proprietary command
362 pdu = '80d4020010' + p['ki']
363 data, sw = self._scc._tp.send_apdu(pdu)
364
365 # EF.HPLMN
366 r = self._scc.select_file(['3f00', '7f20', '6f30'])
367 size = int(r[-1][4:8], 16)
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400368 hplmn = enc_plmn(p['mcc'], p['mnc'])
Harald Welte3156d902011-03-22 21:48:19 +0100369 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
370
371 # EF.SPN (Service Provider Name)
372 r = self._scc.select_file(['3f00', '7f20', '6f30'])
373 size = int(r[-1][4:8], 16)
374 # FIXME
375
376 # FIXME: EF.MSISDN
377
378 def erase(self):
379 return
Sylvain Munaut76504e02010-12-07 00:24:32 +0100380
Harald Weltee10394b2011-12-07 12:34:14 +0100381class SysmoSIMgr1(GrcardSim):
382 """
383 sysmocom sysmoSIM-GR1
384 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
385 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
386 """
387 name = 'sysmosim-gr1'
388
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200389
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100390class SysmoUSIMgr1(Card):
391 """
392 sysmocom sysmoUSIM-GR1
393 """
394 name = 'sysmoUSIM-GR1'
395
396 @classmethod
397 def autodetect(kls, scc):
398 # TODO: Access the ATR
399 return None
400
401 def program(self, p):
402 # TODO: check if verify_chv could be used or what it needs
403 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
404 # Unlock the card..
405 data, sw = self._scc._tp.send_apdu_checksw("0020000A083332323133323332")
406
407 # TODO: move into SimCardCommands
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100408 par = ( p['ki'] + # 16b K
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400409 p['opc'] + # 32b OPC
410 enc_iccid(p['iccid']) + # 10b ICCID
411 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100412 )
413 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
414
415 def erase(self):
416 return
417
Sylvain Munaut053c8952013-07-02 15:12:32 +0200418
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100419class SysmoSIMgr2(Card):
420 """
421 sysmocom sysmoSIM-GR2
422 """
423
424 name = 'sysmoSIM-GR2'
425
426 @classmethod
427 def autodetect(kls, scc):
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900428 try:
429 # Look for ATR
430 if scc.get_atr() == toBytes("3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68"):
431 return kls(scc)
432 except:
433 return None
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100434 return None
435
436 def program(self, p):
437
438 # select MF
439 r = self._scc.select_file(['3f00'])
440
441 # authenticate as SUPER ADM using default key
442 self._scc.verify_chv(0x0b, h2b("3838383838383838"))
443
444 # set ADM pin using proprietary command
445 # INS: D4
446 # P1: 3A for PIN, 3B for PUK
447 # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
448 # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
Jan Balkec3ebd332015-01-26 12:22:55 +0100449 if p['pin_adm']:
450 pin = p['pin_adm']
451 else:
452 pin = h2b("4444444444444444")
453
454 pdu = 'A0D43A0508' + b2h(pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100455 data, sw = self._scc._tp.send_apdu(pdu)
456
457 # authenticate as ADM (enough to write file, and can set PINs)
Jan Balkec3ebd332015-01-26 12:22:55 +0100458
459 self._scc.verify_chv(0x05, pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100460
461 # write EF.ICCID
462 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
463
464 # select DF_GSM
465 r = self._scc.select_file(['7f20'])
466
467 # write EF.IMSI
468 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
469
470 # write EF.ACC
471 if p.get('acc') is not None:
472 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
473
474 # get size and write EF.HPLMN
475 r = self._scc.select_file(['6f30'])
476 size = int(r[-1][4:8], 16)
477 hplmn = enc_plmn(p['mcc'], p['mnc'])
478 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
479
480 # set COMP128 version 0 in proprietary file
481 data, sw = self._scc.update_binary('0001', '001000')
482
483 # set Ki in proprietary file
484 data, sw = self._scc.update_binary('0001', p['ki'], 3)
485
486 # select DF_TELECOM
487 r = self._scc.select_file(['3f00', '7f10'])
488
489 # write EF.SMSP
490 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
491
492 def erase(self):
493 return
494
Jan Balke3e840672015-01-26 15:36:27 +0100495class SysmoUSIMSJS1(Card):
496 """
497 sysmocom sysmoUSIM-SJS1
498 """
499
500 name = 'sysmoUSIM-SJS1'
501
502 def __init__(self, ssc):
503 super(SysmoUSIMSJS1, self).__init__(ssc)
504 self._scc.cla_byte = "00"
Philipp Maier41460862017-03-21 12:05:30 +0100505 self._scc.sel_ctrl = "000C"
Jan Balke3e840672015-01-26 15:36:27 +0100506
507 @classmethod
508 def autodetect(kls, scc):
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900509 try:
510 # Look for ATR
511 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"):
512 return kls(scc)
513 except:
514 return None
Jan Balke3e840672015-01-26 15:36:27 +0100515 return None
516
517 def program(self, p):
518
Philipp Maiere9604882017-03-21 17:24:31 +0100519 # authenticate as ADM using default key (written on the card..)
520 if not p['pin_adm']:
521 raise ValueError("Please provide a PIN-ADM as there is no default one")
522 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
Jan Balke3e840672015-01-26 15:36:27 +0100523
524 # select MF
525 r = self._scc.select_file(['3f00'])
526
Philipp Maiere9604882017-03-21 17:24:31 +0100527 # write EF.ICCID
528 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
529
Jan Balke3e840672015-01-26 15:36:27 +0100530 # select DF_GSM
531 r = self._scc.select_file(['7f20'])
532
Jan Balke3e840672015-01-26 15:36:27 +0100533 # set Ki in proprietary file
534 data, sw = self._scc.update_binary('00FF', p['ki'])
535
Philipp Maier1be35bf2018-07-13 11:29:03 +0200536 # set OPc in proprietary file
Jan Balke3e840672015-01-26 15:36:27 +0100537 content = "01" + p['opc']
538 data, sw = self._scc.update_binary('00F7', content)
539
540
541 # write EF.IMSI
542 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
543
Daniel Willmann1d087ef2017-08-31 10:08:45 +0200544 # EF.SMSP
545 r = self._scc.select_file(['3f00', '7f10'])
546 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 104), force_len=True)
Jan Balke3e840672015-01-26 15:36:27 +0100547
Alexander Chemerise0d9d882018-01-10 14:18:32 +0900548 def erase(self):
549 return
550
551
552class FairwavesSIM(Card):
553 """
554 FairwavesSIM
555
556 The SIM card is operating according to the standard.
557 For Ki/OP/OPC programming the following files are additionally open for writing:
558 3F00/7F20/FF01 – OP/OPC:
559 byte 1 = 0x01, bytes 2-17: OPC;
560 byte 1 = 0x00, bytes 2-17: OP;
561 3F00/7F20/FF02: Ki
562 """
563
564 name = 'Fairwaves SIM'
565 # Propriatary files
566 _EF_num = {
567 'Ki': 'FF02',
568 'OP/OPC': 'FF01',
569 }
570 _EF = {
571 'Ki': DF['GSM']+[_EF_num['Ki']],
572 'OP/OPC': DF['GSM']+[_EF_num['OP/OPC']],
573 }
574
575 def __init__(self, ssc):
576 super(FairwavesSIM, self).__init__(ssc)
577 self._adm_chv_num = 0x11
578 self._adm2_chv_num = 0x12
579
580
581 @classmethod
582 def autodetect(kls, scc):
583 try:
584 # Look for ATR
585 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"):
586 return kls(scc)
587 except:
588 return None
589 return None
590
591
592 def verify_adm2(self, key):
593 '''
594 Authenticate with ADM2 key.
595
596 Fairwaves SIM cards support hierarchical key structure and ADM2 key
597 is a key which has access to proprietary files (Ki and OP/OPC).
598 That said, ADM key inherits permissions of ADM2 key and thus we rarely
599 need ADM2 key per se.
600 '''
601 (res, sw) = self._scc.verify_chv(self._adm2_chv_num, key)
602 return sw
603
604
605 def read_ki(self):
606 """
607 Read Ki in proprietary file.
608
609 Requires ADM1 access level
610 """
611 return self._scc.read_binary(self._EF['Ki'])
612
613
614 def update_ki(self, ki):
615 """
616 Set Ki in proprietary file.
617
618 Requires ADM1 access level
619 """
620 data, sw = self._scc.update_binary(self._EF['Ki'], ki)
621 return sw
622
623
624 def read_op_opc(self):
625 """
626 Read Ki in proprietary file.
627
628 Requires ADM1 access level
629 """
630 (ef, sw) = self._scc.read_binary(self._EF['OP/OPC'])
631 type = 'OP' if ef[0:2] == '00' else 'OPC'
632 return ((type, ef[2:]), sw)
633
634
635 def update_op(self, op):
636 """
637 Set OP in proprietary file.
638
639 Requires ADM1 access level
640 """
641 content = '00' + op
642 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
643 return sw
644
645
646 def update_opc(self, opc):
647 """
648 Set OPC in proprietary file.
649
650 Requires ADM1 access level
651 """
652 content = '01' + opc
653 data, sw = self._scc.update_binary(self._EF['OP/OPC'], content)
654 return sw
655
656
657 def program(self, p):
658 # authenticate as ADM1
659 if not p['pin_adm']:
660 raise ValueError("Please provide a PIN-ADM as there is no default one")
661 sw = self.verify_adm(h2b(p['pin_adm']))
662 if sw != '9000':
663 raise RuntimeError('Failed to authenticate with ADM key %s'%(p['pin_adm'],))
664
665 # TODO: Set operator name
666 if p.get('smsp') is not None:
667 sw = self.update_smsp(p['smsp'])
668 if sw != '9000':
669 print("Programming SMSP failed with code %s"%sw)
670 # This SIM doesn't support changing ICCID
671 if p.get('mcc') is not None and p.get('mnc') is not None:
672 sw = self.update_hplmn_act(p['mcc'], p['mnc'])
673 if sw != '9000':
674 print("Programming MCC/MNC failed with code %s"%sw)
675 if p.get('imsi') is not None:
676 sw = self.update_imsi(p['imsi'])
677 if sw != '9000':
678 print("Programming IMSI failed with code %s"%sw)
679 if p.get('ki') is not None:
680 sw = self.update_ki(p['ki'])
681 if sw != '9000':
682 print("Programming Ki failed with code %s"%sw)
683 if p.get('opc') is not None:
684 sw = self.update_opc(p['opc'])
685 if sw != '9000':
686 print("Programming OPC failed with code %s"%sw)
687 if p.get('acc') is not None:
688 sw = self.update_acc(p['acc'])
689 if sw != '9000':
690 print("Programming ACC failed with code %s"%sw)
Jan Balke3e840672015-01-26 15:36:27 +0100691
692 def erase(self):
693 return
694
695
Todd Neal9eeadfc2018-04-25 15:36:29 -0500696class OpenCellsSim(Card):
697 """
698 OpenCellsSim
699
700 """
701
702 name = 'OpenCells SIM'
703
704 def __init__(self, ssc):
705 super(OpenCellsSim, self).__init__(ssc)
706 self._adm_chv_num = 0x0A
707
708
709 @classmethod
710 def autodetect(kls, scc):
711 try:
712 # Look for ATR
713 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"):
714 return kls(scc)
715 except:
716 return None
717 return None
718
719
720 def program(self, p):
721 if not p['pin_adm']:
722 raise ValueError("Please provide a PIN-ADM as there is no default one")
723 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
724
725 # select MF
726 r = self._scc.select_file(['3f00'])
727
728 # write EF.ICCID
729 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
730
731 r = self._scc.select_file(['7ff0'])
732
733 # set Ki in proprietary file
734 data, sw = self._scc.update_binary('FF02', p['ki'])
735
736 # set OPC in proprietary file
737 data, sw = self._scc.update_binary('FF01', p['opc'])
738
739 # select DF_GSM
740 r = self._scc.select_file(['7f20'])
741
742 # write EF.IMSI
743 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
744
745
746# In order for autodetection ...
Harald Weltee10394b2011-12-07 12:34:14 +0100747_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
Alexander Chemerise0d9d882018-01-10 14:18:32 +0900748 SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1,
Todd Neal9eeadfc2018-04-25 15:36:29 -0500749 FairwavesSIM, OpenCellsSim ]
Alexander Chemeris8ad124a2018-01-10 14:17:55 +0900750
751def card_autodetect(scc):
752 for kls in _cards_classes:
753 card = kls.autodetect(scc)
754 if card is not None:
755 card.reset()
756 return card
757 return None