blob: 5a88b04373a76540fe910eb4d9695b518c34b6df [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
267 self._scc.verify_chv(5, h2b("4444444444444444"))
268
269 # EF.ICCID
270 r = self._scc.select_file(['3f00', '2fe2'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400271 data, sw = self._scc.update_binary('2fe2', enc_iccid(p['iccid']))
Harald Welte3156d902011-03-22 21:48:19 +0100272
273 # EF.IMSI
274 r = self._scc.select_file(['3f00', '7f20', '6f07'])
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400275 data, sw = self._scc.update_binary('6f07', enc_imsi(p['imsi']))
Harald Welte3156d902011-03-22 21:48:19 +0100276
277 # EF.ACC
Alexander Chemeris21885242013-07-02 16:56:55 +0400278 if p.get('acc') is not None:
279 data, sw = self._scc.update_binary('6f78', lpad(p['acc'], 4))
Harald Welte3156d902011-03-22 21:48:19 +0100280
281 # EF.SMSP
282 r = self._scc.select_file(['3f00', '7f10', '6f42'])
Sylvain Munaut8ca49e92011-12-10 09:57:50 +0100283 data, sw = self._scc.update_record('6f42', 1, lpad(p['smsp'], 80))
Harald Welte3156d902011-03-22 21:48:19 +0100284
285 # Set the Ki using proprietary command
286 pdu = '80d4020010' + p['ki']
287 data, sw = self._scc._tp.send_apdu(pdu)
288
289 # EF.HPLMN
290 r = self._scc.select_file(['3f00', '7f20', '6f30'])
291 size = int(r[-1][4:8], 16)
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400292 hplmn = enc_plmn(p['mcc'], p['mnc'])
Harald Welte3156d902011-03-22 21:48:19 +0100293 self._scc.update_binary('6f30', hplmn + 'ff' * (size-3))
294
295 # EF.SPN (Service Provider Name)
296 r = self._scc.select_file(['3f00', '7f20', '6f30'])
297 size = int(r[-1][4:8], 16)
298 # FIXME
299
300 # FIXME: EF.MSISDN
301
302 def erase(self):
303 return
Sylvain Munaut76504e02010-12-07 00:24:32 +0100304
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200305
Harald Weltee10394b2011-12-07 12:34:14 +0100306class SysmoSIMgr1(GrcardSim):
307 """
308 sysmocom sysmoSIM-GR1
309 These cards have a much more regular ISO 7816-4 / TS 11.11 structure,
310 and use standard UPDATE RECORD / UPDATE BINARY commands except for Ki.
311 """
312 name = 'sysmosim-gr1'
313
Sylvain Munaut5da8d4e2013-07-02 15:13:24 +0200314
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100315class SysmoUSIMgr1(Card):
316 """
317 sysmocom sysmoUSIM-GR1
318 """
319 name = 'sysmoUSIM-GR1'
320
321 @classmethod
322 def autodetect(kls, scc):
323 # TODO: Access the ATR
324 return None
325
326 def program(self, p):
327 # TODO: check if verify_chv could be used or what it needs
328 # self._scc.verify_chv(0x0A, [0x33,0x32,0x32,0x31,0x33,0x32,0x33,0x32])
329 # Unlock the card..
330 data, sw = self._scc._tp.send_apdu_checksw("0020000A083332323133323332")
331
332 # TODO: move into SimCardCommands
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100333 par = ( p['ki'] + # 16b K
Alexander Chemeris7be92ff2013-07-10 11:18:06 +0400334 p['opc'] + # 32b OPC
335 enc_iccid(p['iccid']) + # 10b ICCID
336 enc_imsi(p['imsi']) # 9b IMSI_len + id_type(9) + IMSI
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100337 )
338 data, sw = self._scc._tp.send_apdu_checksw("0099000033" + par)
339
340 def erase(self):
341 return
342
Sylvain Munaut053c8952013-07-02 15:12:32 +0200343
344 # In order for autodetection ...
Harald Weltee10394b2011-12-07 12:34:14 +0100345_cards_classes = [ FakeMagicSim, SuperSim, MagicSim, GrcardSim,
Holger Hans Peter Freyther4d91bf42012-03-22 14:28:38 +0100346 SysmoSIMgr1, SysmoUSIMgr1 ]