blob: f87e45a14ea86ca7906e152f7e784733767e8c13 [file] [log] [blame]
Harald Weltef44256c2021-10-14 15:53:39 +02001# coding=utf-8
2"""Utilities / Functions related to sysmocom SJA2 cards
3
4(C) 2021 by Harald Welte <laforge@osmocom.org>
5
6This program is free software: you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation, either version 2 of the License, or
9(at your option) any later version.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program. If not, see <http://www.gnu.org/licenses/>.
18"""
19
20from pytlv.TLV import *
21from struct import pack, unpack
22from pySim.utils import *
23from pySim.filesystem import *
24from pySim.ts_102_221 import CardProfileUICC
25from pySim.construct import *
26from construct import *
27import pySim
28
29key_type2str = {
30 0: 'kic',
31 1: 'kid',
32 2: 'kik',
33 3: 'any',
34}
35
36key_algo2str = {
37 0: 'des',
38 1: 'aes'
39}
40
41mac_length = {
42 0: 8,
43 1: 4
44}
45
Harald Weltec91085e2022-02-10 18:05:45 +010046
Harald Weltef44256c2021-10-14 15:53:39 +020047class EF_PIN(TransparentEF):
48 def __init__(self, fid, name):
49 super().__init__(fid, name=name, desc='%s PIN file' % name)
Harald Weltec91085e2022-02-10 18:05:45 +010050
Harald Weltef44256c2021-10-14 15:53:39 +020051 def _decode_bin(self, raw_bin_data):
52 u = unpack('!BBB8s', raw_bin_data[:11])
Harald Weltec91085e2022-02-10 18:05:45 +010053 res = {'enabled': (True, False)[u[0] & 0x01],
54 'initialized': (True, False)[u[0] & 0x02],
55 'disable_able': (False, True)[u[0] & 0x10],
56 'unblock_able': (False, True)[u[0] & 0x20],
57 'change_able': (False, True)[u[0] & 0x40],
58 'valid': (False, True)[u[0] & 0x80],
59 'attempts_remaining': u[1],
60 'maximum_attempts': u[2],
61 'pin': u[3].hex(),
62 }
Harald Weltef44256c2021-10-14 15:53:39 +020063 if len(raw_bin_data) == 21:
64 u2 = unpack('!BB8s', raw_bin_data[11:10])
65 res['attempts_remaining_puk'] = u2[0]
66 res['maximum_attempts_puk'] = u2[1]
67 res['puk'] = u2[2].hex()
68 return res
69
Harald Weltec91085e2022-02-10 18:05:45 +010070
Harald Weltef44256c2021-10-14 15:53:39 +020071class EF_MILENAGE_CFG(TransparentEF):
72 def __init__(self, fid='6f21', name='EF.MILENAGE_CFG', desc='Milenage connfiguration'):
73 super().__init__(fid, name=name, desc=desc)
Harald Weltec91085e2022-02-10 18:05:45 +010074
Harald Weltef44256c2021-10-14 15:53:39 +020075 def _decode_bin(self, raw_bin_data):
76 u = unpack('!BBBBB16s16s16s16s16s', raw_bin_data)
77 return {'r1': u[0], 'r2': u[1], 'r3': u[2], 'r4': u[3], 'r5': u[4],
78 'c1': u[5].hex(),
79 'c2': u[6].hex(),
80 'c3': u[7].hex(),
81 'c4': u[8].hex(),
82 'c5': u[9].hex(),
Harald Weltec91085e2022-02-10 18:05:45 +010083 }
84
Harald Weltef44256c2021-10-14 15:53:39 +020085
86class EF_0348_KEY(LinFixedEF):
87 def __init__(self, fid='6f22', name='EF.0348_KEY', desc='TS 03.48 OTA Keys'):
Harald Weltec91085e2022-02-10 18:05:45 +010088 super().__init__(fid, name=name, desc=desc, rec_len={27, 35})
89
Harald Weltef44256c2021-10-14 15:53:39 +020090 def _decode_record_bin(self, raw_bin_data):
91 u = unpack('!BBB', raw_bin_data[0:3])
92 key_algo = (u[2] >> 6) & 1
93 key_length = ((u[2] >> 3) & 3) * 8
94 return {'sec_domain': u[0],
95 'key_set_version': u[1],
96 'key_type': key_type2str[u[2] & 3],
97 'key_length': key_length,
98 'algorithm': key_algo2str[key_algo],
99 'mac_length': mac_length[(u[2] >> 7)],
100 'key': raw_bin_data[3:key_length].hex()
Harald Weltec91085e2022-02-10 18:05:45 +0100101 }
102
Harald Weltef44256c2021-10-14 15:53:39 +0200103
104class EF_0348_COUNT(LinFixedEF):
105 def __init__(self, fid='6f23', name='EF.0348_COUNT', desc='TS 03.48 OTA Counters'):
Harald Weltec91085e2022-02-10 18:05:45 +0100106 super().__init__(fid, name=name, desc=desc, rec_len={7, 7})
107
Harald Weltef44256c2021-10-14 15:53:39 +0200108 def _decode_record_bin(self, raw_bin_data):
109 u = unpack('!BB5s', raw_bin_data)
110 return {'sec_domain': u[0], 'key_set_version': u[1], 'counter': u[2]}
111
Harald Weltec91085e2022-02-10 18:05:45 +0100112
Harald Weltef44256c2021-10-14 15:53:39 +0200113class EF_SIM_AUTH_COUNTER(TransparentEF):
114 def __init__(self, fid='af24', name='EF.SIM_AUTH_COUNTER'):
115 super().__init__(fid, name=name, desc='Number of remaining RUN GSM ALGORITHM executions')
116 self._construct = Struct('num_run_gsm_algo_remain'/Int32ub)
117
Harald Weltec91085e2022-02-10 18:05:45 +0100118
Harald Weltef44256c2021-10-14 15:53:39 +0200119class EF_GP_COUNT(LinFixedEF):
120 def __init__(self, fid='6f26', name='EF.GP_COUNT', desc='GP SCP02 Counters'):
Harald Weltec91085e2022-02-10 18:05:45 +0100121 super().__init__(fid, name=name, desc=desc, rec_len={5, 5})
122
Harald Weltef44256c2021-10-14 15:53:39 +0200123 def _decode_record_bin(self, raw_bin_data):
124 u = unpack('!BBHB', raw_bin_data)
125 return {'sec_domain': u[0], 'key_set_version': u[1], 'counter': u[2], 'rfu': u[3]}
126
Harald Weltec91085e2022-02-10 18:05:45 +0100127
Harald Weltef44256c2021-10-14 15:53:39 +0200128class EF_GP_DIV_DATA(LinFixedEF):
129 def __init__(self, fid='6f27', name='EF.GP_DIV_DATA', desc='GP SCP02 key diversification data'):
Harald Weltec91085e2022-02-10 18:05:45 +0100130 super().__init__(fid, name=name, desc=desc, rec_len={12, 12})
131
Harald Weltef44256c2021-10-14 15:53:39 +0200132 def _decode_record_bin(self, raw_bin_data):
133 u = unpack('!BB8s', raw_bin_data)
134 return {'sec_domain': u[0], 'key_set_version': u[1], 'key_div_data': u[2].hex()}
135
Harald Weltec91085e2022-02-10 18:05:45 +0100136
Harald Weltef44256c2021-10-14 15:53:39 +0200137class EF_SIM_AUTH_KEY(TransparentEF):
138 def __init__(self, fid='6f20', name='EF.SIM_AUTH_KEY'):
139 super().__init__(fid, name=name, desc='USIM authentication key')
140 CfgByte = BitStruct(Bit[2],
141 'use_sres_deriv_func_2'/Bit,
142 'use_opc_instead_of_op'/Bit,
143 'algorithm'/Enum(Nibble, milenage=4, comp128v1=1, comp128v2=2, comp128v3=3))
144 self._construct = Struct('cfg'/CfgByte,
145 'key'/Bytes(16),
Harald Weltec91085e2022-02-10 18:05:45 +0100146 'op' /
147 If(this.cfg.algorithm == 'milenage' and not this.cfg.use_opc_instead_of_op, Bytes(
148 16)),
149 'opc' /
150 If(this.cfg.algorithm == 'milenage' and this.cfg.use_opc_instead_of_op, Bytes(
151 16))
Harald Weltef44256c2021-10-14 15:53:39 +0200152 )
153
Harald Weltec91085e2022-02-10 18:05:45 +0100154
Harald Weltef44256c2021-10-14 15:53:39 +0200155class DF_SYSTEM(CardDF):
156 def __init__(self):
157 super().__init__(fid='a515', name='DF.SYSTEM', desc='CardOS specifics')
158 files = [
159 EF_PIN('6f01', 'EF.CHV1'),
160 EF_PIN('6f81', 'EF.CHV2'),
161 EF_PIN('6f0a', 'EF.ADM1'),
162 EF_PIN('6f0b', 'EF.ADM2'),
163 EF_PIN('6f0c', 'EF.ADM3'),
164 EF_PIN('6f0d', 'EF.ADM4'),
165 EF_MILENAGE_CFG(),
166 EF_0348_KEY(),
167 EF_SIM_AUTH_COUNTER(),
168 EF_SIM_AUTH_KEY(),
169 EF_0348_COUNT(),
170 EF_GP_COUNT(),
171 EF_GP_DIV_DATA(),
Harald Weltec91085e2022-02-10 18:05:45 +0100172 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200173 self.add_files(files)
174
175 def decode_select_response(self, resp_hex):
Philipp Maier5998a3a2021-11-16 15:16:39 +0100176 return pySim.ts_102_221.CardProfileUICC.decode_select_response(resp_hex)
Harald Weltef44256c2021-10-14 15:53:39 +0200177
Harald Weltec91085e2022-02-10 18:05:45 +0100178
Harald Weltef44256c2021-10-14 15:53:39 +0200179class EF_USIM_SQN(TransparentEF):
180 def __init__(self, fid='af30', name='EF.USIM_SQN'):
181 super().__init__(fid, name=name, desc='SQN parameters for AKA')
182 Flag1 = BitStruct('skip_next_sqn_check'/Bit, 'delta_max_check'/Bit,
183 'age_limit_check'/Bit, 'sqn_check'/Bit,
184 'ind_len'/BitsInteger(4))
185 Flag2 = BitStruct('rfu'/BitsRFU(5), 'dont_clear_amf_for_macs'/Bit,
186 'aus_concealed'/Bit, 'autn_concealed'/Bit)
187 self._construct = Struct('flag1'/Flag1, 'flag2'/Flag2,
Harald Weltec91085e2022-02-10 18:05:45 +0100188 'delta_max' /
189 BytesInteger(6), 'age_limit'/BytesInteger(6),
Harald Welteeb458382021-10-16 10:44:23 +0200190 'freshness'/GreedyRange(BytesInteger(6)))
Harald Weltef44256c2021-10-14 15:53:39 +0200191
Harald Weltec91085e2022-02-10 18:05:45 +0100192
Harald Weltef44256c2021-10-14 15:53:39 +0200193class EF_USIM_AUTH_KEY(TransparentEF):
194 def __init__(self, fid='af20', name='EF.USIM_AUTH_KEY'):
195 super().__init__(fid, name=name, desc='USIM authentication key')
196 CfgByte = BitStruct(Bit, 'only_4bytes_res_in_3g'/Bit,
197 'use_sres_deriv_func_2_in_3g'/Bit,
198 'use_opc_instead_of_op'/Bit,
199 'algorithm'/Enum(Nibble, milenage=4, sha1_aka=5, xor=15))
200 self._construct = Struct('cfg'/CfgByte,
201 'key'/Bytes(16),
Harald Weltec91085e2022-02-10 18:05:45 +0100202 'op' /
203 If(this.cfg.algorithm == 'milenage' and not this.cfg.use_opc_instead_of_op, Bytes(
204 16)),
205 'opc' /
206 If(this.cfg.algorithm == 'milenage' and this.cfg.use_opc_instead_of_op, Bytes(
207 16))
Harald Weltef44256c2021-10-14 15:53:39 +0200208 )
Harald Weltec91085e2022-02-10 18:05:45 +0100209
210
Harald Weltef44256c2021-10-14 15:53:39 +0200211class EF_USIM_AUTH_KEY_2G(TransparentEF):
212 def __init__(self, fid='af22', name='EF.USIM_AUTH_KEY_2G'):
213 super().__init__(fid, name=name, desc='USIM authentication key in 2G context')
214 CfgByte = BitStruct(Bit, 'only_4bytes_res_in_3g'/Bit,
215 'use_sres_deriv_func_2_in_3g'/Bit,
216 'use_opc_instead_of_op'/Bit,
217 'algorithm'/Enum(Nibble, milenage=4, comp128v1=1, comp128v2=2, comp128v3=3))
218 self._construct = Struct('cfg'/CfgByte,
219 'key'/Bytes(16),
Harald Weltec91085e2022-02-10 18:05:45 +0100220 'op' /
221 If(this.cfg.algorithm == 'milenage' and not this.cfg.use_opc_instead_of_op, Bytes(
222 16)),
223 'opc' /
224 If(this.cfg.algorithm == 'milenage' and this.cfg.use_opc_instead_of_op, Bytes(
225 16))
Harald Weltef44256c2021-10-14 15:53:39 +0200226 )
Harald Weltec91085e2022-02-10 18:05:45 +0100227
228
Harald Weltef44256c2021-10-14 15:53:39 +0200229class EF_GBA_SK(TransparentEF):
230 def __init__(self, fid='af31', name='EF.GBA_SK'):
231 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
232 self._construct = GreedyBytes
233
Harald Weltec91085e2022-02-10 18:05:45 +0100234
Harald Weltef44256c2021-10-14 15:53:39 +0200235class EF_GBA_REC_LIST(TransparentEF):
236 def __init__(self, fid='af32', name='EF.GBA_REC_LIST'):
237 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
238 # integers representing record numbers in EF-GBANL
239 self._construct = GreedyRange(Int8ub)
240
Harald Weltec91085e2022-02-10 18:05:45 +0100241
Harald Weltef44256c2021-10-14 15:53:39 +0200242class EF_GBA_INT_KEY(LinFixedEF):
243 def __init__(self, fid='af33', name='EF.GBA_INT_KEY'):
Harald Weltec91085e2022-02-10 18:05:45 +0100244 super().__init__(fid, name=name,
245 desc='Secret key for GBA key derivation', rec_len={32, 32})
Harald Weltef44256c2021-10-14 15:53:39 +0200246 self._construct = GreedyBytes
247
248
Harald Weltef44256c2021-10-14 15:53:39 +0200249class SysmocomSJA2(CardModel):
Harald Weltec91085e2022-02-10 18:05:45 +0100250 _atrs = ["3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9",
251 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2",
252 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"]
253
Harald Weltef44256c2021-10-14 15:53:39 +0200254 @classmethod
Harald Weltec91085e2022-02-10 18:05:45 +0100255 def add_files(cls, rs: RuntimeState):
Harald Weltef44256c2021-10-14 15:53:39 +0200256 """Add sysmocom SJA2 specific files to given RuntimeState."""
257 rs.mf.add_file(DF_SYSTEM())
258 # optional USIM application
259 if 'a0000000871002' in rs.mf.applications:
260 usim_adf = rs.mf.applications['a0000000871002']
261 files_adf_usim = [
262 EF_USIM_AUTH_KEY(),
263 EF_USIM_AUTH_KEY_2G(),
264 EF_GBA_SK(),
265 EF_GBA_REC_LIST(),
266 EF_GBA_INT_KEY(),
267 EF_USIM_SQN(),
Harald Weltec91085e2022-02-10 18:05:45 +0100268 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200269 usim_adf.add_files(files_adf_usim)
270 # optional ISIM application
271 if 'a0000000871004' in rs.mf.applications:
272 isim_adf = rs.mf.applications['a0000000871004']
273 files_adf_isim = [
274 EF_USIM_AUTH_KEY(name='EF.ISIM_AUTH_KEY'),
275 EF_USIM_AUTH_KEY_2G(name='EF.ISIM_AUTH_KEY_2G'),
276 EF_USIM_SQN(name='EF.ISIM_SQN'),
Harald Weltec91085e2022-02-10 18:05:45 +0100277 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200278 isim_adf.add_files(files_adf_isim)