blob: 925c5e63b1766af928e075bf0e0e37953fa0b040 [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>
Sylvain Munaut76504e02010-12-07 00:24:32 +010010#
11# This program is free software: you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation, either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program. If not, see <http://www.gnu.org/licenses/>.
23#
24
Alexander Chemeris7be92ff2013-07-10 11:18:06 +040025from pySim.utils import b2h, h2b, swap_nibbles, rpad, lpad, enc_imsi, enc_iccid, enc_plmn
Sylvain Munaut76504e02010-12-07 00:24:32 +010026
27
28class Card(object):
29
30 def __init__(self, scc):
31 self._scc = scc
32
Sylvain Munaut76504e02010-12-07 00:24:32 +010033 def reset(self):
34 self._scc.reset_card()
35
36
37class _MagicSimBase(Card):
38 """
39 Theses cards uses several record based EFs to store the provider infos,
40 each possible provider uses a specific record number in each EF. The
41 indexes used are ( where N is the number of providers supported ) :
42 - [2 .. N+1] for the operator name
43 - [1 .. N] for the programable EFs
44
45 * 3f00/7f4d/8f0c : Operator Name
46
47 bytes 0-15 : provider name, padded with 0xff
48 byte 16 : length of the provider name
49 byte 17 : 01 for valid records, 00 otherwise
50
51 * 3f00/7f4d/8f0d : Programmable Binary EFs
52
53 * 3f00/7f4d/8f0e : Programmable Record EFs
54
55 """
56
57 @classmethod
58 def autodetect(kls, scc):
59 try:
60 for p, l, t in kls._files.values():
61 if not t:
62 continue
63 if scc.record_size(['3f00', '7f4d', p]) != l:
64 return None
65 except:
66 return None
67
68 return kls(scc)
69
70 def _get_count(self):
71 """
72 Selects the file and returns the total number of entries
73 and entry size
74 """
75 f = self._files['name']
76
77 r = self._scc.select_file(['3f00', '7f4d', f[0]])
78 rec_len = int(r[-1][28:30], 16)
79 tlen = int(r[-1][4:8],16)
80 rec_cnt = (tlen / rec_len) - 1;
81
82 if (rec_cnt < 1) or (rec_len != f[1]):
83 raise RuntimeError('Bad card type')
84
85 return rec_cnt
86
87 def program(self, p):
88 # Go to dir
89 self._scc.select_file(['3f00', '7f4d'])
90
91 # Home PLMN in PLMN_Sel format
Alexander Chemeris7be92ff2013-07-10 11:18:06 +040092 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +010093
94 # Operator name ( 3f00/7f4d/8f0c )
95 self._scc.update_record(self._files['name'][0], 2,
96 rpad(b2h(p['name']), 32) + ('%02x' % len(p['name'])) + '01'
97 )
98
99 # ICCID/IMSI/Ki/HPLMN ( 3f00/7f4d/8f0d )
100 v = ''
101
102 # inline Ki
103 if self._ki_file is None:
104 v += p['ki']
105
106 # ICCID
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400107 v += '3f00' + '2fe2' + '0a' + enc_iccid(p['iccid'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100108
109 # IMSI
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400110 v += '7f20' + '6f07' + '09' + enc_imsi(p['imsi'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100111
112 # Ki
113 if self._ki_file:
114 v += self._ki_file + '10' + p['ki']
115
116 # PLMN_Sel
117 v+= '6f30' + '18' + rpad(hplmn, 36)
118
Alexander Chemeris21885242013-07-02 16:56:55 +0400119 # ACC
120 # This doesn't work with "fake" SuperSIM cards,
121 # but will hopefully work with real SuperSIMs.
122 if p.get('acc') is not None:
123 v+= '6f78' + '02' + lpad(p['acc'], 4)
124
Sylvain Munaut76504e02010-12-07 00:24:32 +0100125 self._scc.update_record(self._files['b_ef'][0], 1,
126 rpad(v, self._files['b_ef'][1]*2)
127 )
128
129 # SMSP ( 3f00/7f4d/8f0e )
130 # FIXME
131
132 # Write PLMN_Sel forcefully as well
133 r = self._scc.select_file(['3f00', '7f20', '6f30'])
134 tl = int(r[-1][4:8], 16)
135
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400136 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100137 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
138
139 def erase(self):
140 # Dummy
141 df = {}
142 for k, v in self._files.iteritems():
143 ofs = 1
144 fv = v[1] * 'ff'
145 if k == 'name':
146 ofs = 2
147 fv = fv[0:-4] + '0000'
148 df[v[0]] = (fv, ofs)
149
150 # Write
151 for n in range(0,self._get_count()):
152 for k, (msg, ofs) in df.iteritems():
153 self._scc.update_record(['3f00', '7f4d', k], n + ofs, msg)
154
155
156class SuperSim(_MagicSimBase):
157
158 name = 'supersim'
159
160 _files = {
161 'name' : ('8f0c', 18, True),
162 'b_ef' : ('8f0d', 74, True),
163 'r_ef' : ('8f0e', 50, True),
164 }
165
166 _ki_file = None
167
168
169class MagicSim(_MagicSimBase):
170
171 name = 'magicsim'
172
173 _files = {
174 'name' : ('8f0c', 18, True),
175 'b_ef' : ('8f0d', 130, True),
176 'r_ef' : ('8f0e', 102, False),
177 }
178
179 _ki_file = '6f1b'
180
181
182class FakeMagicSim(Card):
183 """
184 Theses cards have a record based EF 3f00/000c that contains the provider
185 informations. See the program method for its format. The records go from
186 1 to N.
187 """
188
189 name = 'fakemagicsim'
190
191 @classmethod
192 def autodetect(kls, scc):
193 try:
194 if scc.record_size(['3f00', '000c']) != 0x5a:
195 return None
196 except:
197 return None
198
199 return kls(scc)
200
201 def _get_infos(self):
202 """
203 Selects the file and returns the total number of entries
204 and entry size
205 """
206
207 r = self._scc.select_file(['3f00', '000c'])
208 rec_len = int(r[-1][28:30], 16)
209 tlen = int(r[-1][4:8],16)
210 rec_cnt = (tlen / rec_len) - 1;
211
212 if (rec_cnt < 1) or (rec_len != 0x5a):
213 raise RuntimeError('Bad card type')
214
215 return rec_cnt, rec_len
216
217 def program(self, p):
218 # Home PLMN
219 r = self._scc.select_file(['3f00', '7f20', '6f30'])
220 tl = int(r[-1][4:8], 16)
221
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400222 hplmn = enc_plmn(p['mcc'], p['mnc'])
Sylvain Munaut76504e02010-12-07 00:24:32 +0100223 self._scc.update_binary('6f30', hplmn + 'ff' * (tl-3))
224
225 # Get total number of entries and entry size
226 rec_cnt, rec_len = self._get_infos()
227
228 # Set first entry
229 entry = (
230 '81' + # 1b Status: Valid & Active
231 rpad(b2h(p['name'][0:14]), 28) + # 14b Entry Name
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400232 enc_iccid(p['iccid']) + # 10b ICCID
233 enc_imsi(p['imsi']) + # 9b IMSI_len + id_type(9) + IMSI
Sylvain Munaut76504e02010-12-07 00:24:32 +0100234 p['ki'] + # 16b Ki
Sylvain Munaut8ca49e92011-12-10 09:57:50 +0100235 lpad(p['smsp'], 80) # 40b SMSP (padded with ff if needed)
Sylvain Munaut76504e02010-12-07 00:24:32 +0100236 )
237 self._scc.update_record('000c', 1, entry)
238
239 def erase(self):
240 # Get total number of entries and entry size
241 rec_cnt, rec_len = self._get_infos()
242
243 # Erase all entries
244 entry = 'ff' * rec_len
245 for i in range(0, rec_cnt):
246 self._scc.update_record('000c', 1+i, entry)
247
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200248
Harald Welte3156d902011-03-22 21:48:19 +0100249class GrcardSim(Card):
250 """
251 Greencard (grcard.cn) HZCOS GSM SIM
252 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
253 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
254 """
255
256 name = 'grcardsim'
257
258 @classmethod
259 def autodetect(kls, scc):
260 return None
261
262 def program(self, p):
263 # We don't really know yet what ADM PIN 4 is about
264 #self._scc.verify_chv(4, h2b("4444444444444444"))
265
266 # Authenticate using ADM PIN 5
Jan Balkec3ebd332015-01-26 12:22:55 +0100267 if p['pin_adm']:
268 pin = p['pin_adm']
269 else:
270 pin = h2b("4444444444444444")
271 self._scc.verify_chv(5, pin)
Harald Welte3156d902011-03-22 21:48:19 +0100272
273 # EF.ICCID
274 r = self._scc.select_file(['3f00', '2fe2'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400275 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100276
277 # EF.IMSI
278 r = self._scc.select_file(['3f00', '7f20', '6f07'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400279 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100280
281 # EF.ACC
Alexander Chemeris21885242013-07-02 16:56:55 +0400282 if p.get('acc') is not None:
283 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100284
285 # EF.SMSP
286 r = self._scc.select_file(['3f00', '7f10', '6f42'])
Sylvain Munaut8ca49e92011-12-10 09:57:50 +0100287 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100288
289 # Set the Ki using proprietary command
290 pdu = '80d4020010' + p['ki']
291 data, sw = self._scc._tp.send_apdu(pdu)
292
293 # EF.HPLMN
294 r = self._scc.select_file(['3f00', '7f20', '6f30'])
295 size = int(r[-1][4:8], 16)
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400296 hplmn = enc_plmn(p['mcc'], p['mnc'])
Harald Welte3156d902011-03-22 21:48:19 +0100297 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
298
299 # EF.SPN (Service Provider Name)
300 r = self._scc.select_file(['3f00', '7f20', '6f30'])
301 size = int(r[-1][4:8], 16)
302 # FIXME
303
304 # FIXME: EF.MSISDN
305
306 def erase(self):
307 return
Sylvain Munaut76504e02010-12-07 00:24:32 +0100308
Harald Weltee10394b2011-12-07 12:34:14 +0100309class SysmoSIMgr1(GrcardSim):
310 """
311 sysmocom sysmoSIM-GR1
312 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
313 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
314 """
315 name = 'sysmosim-gr1'
316
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200317
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100318class SysmoUSIMgr1(Card):
319 """
320 sysmocom sysmoUSIM-GR1
321 """
322 name = 'sysmoUSIM-GR1'
323
324 @classmethod
325 def autodetect(kls, scc):
326 # TODO: Access the ATR
327 return None
328
329 def program(self, p):
330 # TODO: check if verify_chv could be used or what it needs
331 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
332 # Unlock the card..
333 data, sw = self._scc._tp.send_apdu_checksw("0020000A083332323133323332")
334
335 # TODO: move into SimCardCommands
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100336 par = ( p['ki'] + # 16b K
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400337 p['opc'] + # 32b OPC
338 enc_iccid(p['iccid']) + # 10b ICCID
339 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100340 )
341 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
342
343 def erase(self):
344 return
345
Sylvain Munaut053c8952013-07-02 15:12:32 +0200346
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100347class SysmoSIMgr2(Card):
348 """
349 sysmocom sysmoSIM-GR2
350 """
351
352 name = 'sysmoSIM-GR2'
353
354 @classmethod
355 def autodetect(kls, scc):
356 # TODO: look for ATR 3B 7D 94 00 00 55 55 53 0A 74 86 93 0B 24 7C 4D 54 68
357 return None
358
359 def program(self, p):
360
361 # select MF
362 r = self._scc.select_file(['3f00'])
363
364 # authenticate as SUPER ADM using default key
365 self._scc.verify_chv(0x0b, h2b("3838383838383838"))
366
367 # set ADM pin using proprietary command
368 # INS: D4
369 # P1: 3A for PIN, 3B for PUK
370 # P2: CHV number, as in VERIFY CHV for PIN, and as in UNBLOCK CHV for PUK
371 # P3: 08, CHV length (curiously the PUK is also 08 length, instead of 10)
Jan Balkec3ebd332015-01-26 12:22:55 +0100372 if p['pin_adm']:
373 pin = p['pin_adm']
374 else:
375 pin = h2b("4444444444444444")
376
377 pdu = 'A0D43A0508' + b2h(pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100378 data, sw = self._scc._tp.send_apdu(pdu)
379
380 # authenticate as ADM (enough to write file, and can set PINs)
Jan Balkec3ebd332015-01-26 12:22:55 +0100381
382 self._scc.verify_chv(0x05, pin)
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100383
384 # write EF.ICCID
385 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
386
387 # select DF_GSM
388 r = self._scc.select_file(['7f20'])
389
390 # write EF.IMSI
391 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
392
393 # write EF.ACC
394 if p.get('acc') is not None:
395 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
396
397 # get size and write EF.HPLMN
398 r = self._scc.select_file(['6f30'])
399 size = int(r[-1][4:8], 16)
400 hplmn = enc_plmn(p['mcc'], p['mnc'])
401 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
402
403 # set COMP128 version 0 in proprietary file
404 data, sw = self._scc.update_binary('0001', '001000')
405
406 # set Ki in proprietary file
407 data, sw = self._scc.update_binary('0001', p['ki'], 3)
408
409 # select DF_TELECOM
410 r = self._scc.select_file(['3f00', '7f10'])
411
412 # write EF.SMSP
413 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
414
415 def erase(self):
416 return
417
Jan Balke3e840672015-01-26 15:36:27 +0100418class SysmoUSIMSJS1(Card):
419 """
420 sysmocom sysmoUSIM-SJS1
421 """
422
423 name = 'sysmoUSIM-SJS1'
424
425 def __init__(self, ssc):
426 super(SysmoUSIMSJS1, self).__init__(ssc)
427 self._scc.cla_byte = "00"
Philipp Maier41460862017-03-21 12:05:30 +0100428 self._scc.sel_ctrl = "000C"
Jan Balke3e840672015-01-26 15:36:27 +0100429
430 @classmethod
431 def autodetect(kls, scc):
432 # TODO: look for ATR 3B 9F 96 80 1F C7 80 31 A0 73 BE 21 13 67 43 20 07 18 00 00 01 A5
433 return None
434
435 def program(self, p):
436
Philipp Maiere9604882017-03-21 17:24:31 +0100437 # authenticate as ADM using default key (written on the card..)
438 if not p['pin_adm']:
439 raise ValueError("Please provide a PIN-ADM as there is no default one")
440 self._scc.verify_chv(0x0A, h2b(p['pin_adm']))
Jan Balke3e840672015-01-26 15:36:27 +0100441
442 # select MF
443 r = self._scc.select_file(['3f00'])
444
Philipp Maiere9604882017-03-21 17:24:31 +0100445 # write EF.ICCID
446 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
447
Jan Balke3e840672015-01-26 15:36:27 +0100448 # select DF_GSM
449 r = self._scc.select_file(['7f20'])
450
Jan Balke3e840672015-01-26 15:36:27 +0100451 # set Ki in proprietary file
452 data, sw = self._scc.update_binary('00FF', p['ki'])
453
454 # set Ki in proprietary file
455 content = "01" + p['opc']
456 data, sw = self._scc.update_binary('00F7', content)
457
458
459 # write EF.IMSI
460 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
461
462
463
464 def erase(self):
465 return
466
467
Sylvain Munaut2fc205c2013-12-23 17:22:56 +0100468
Sylvain Munaut053c8952013-07-02 15:12:32 +0200469 # In order for autodetection ...
Harald Weltee10394b2011-12-07 12:34:14 +0100470_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
Jan Balke3e840672015-01-26 15:36:27 +0100471 SysmoSIMgr1, SysmoSIMgr2, SysmoUSIMgr1, SysmoUSIMSJS1 ]