blob: bfd0ff5e089640732d3544d9706674b27190802e [file] [log] [blame]
Harald Weltef44256c2021-10-14 15:53:39 +02001# coding=utf-8
Harald Welte0489ae62023-05-24 10:28:34 +02002"""Utilities / Functions related to sysmocom SJA2/SJA5 cards
Harald Weltef44256c2021-10-14 15:53:39 +02003
Harald Welte0489ae62023-05-24 10:28:34 +02004(C) 2021-2023 by Harald Welte <laforge@osmocom.org>
Harald Weltef44256c2021-10-14 15:53:39 +02005
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 *
Harald Welte531894d2023-07-11 19:11:11 +020024from pySim.runtime import RuntimeState
Harald Weltef44256c2021-10-14 15:53:39 +020025from pySim.ts_102_221 import CardProfileUICC
26from pySim.construct import *
27from construct import *
28import pySim
29
30key_type2str = {
31 0: 'kic',
32 1: 'kid',
33 2: 'kik',
34 3: 'any',
35}
36
37key_algo2str = {
38 0: 'des',
39 1: 'aes'
40}
41
42mac_length = {
43 0: 8,
44 1: 4
45}
46
Harald Weltec91085e2022-02-10 18:05:45 +010047
Harald Weltef44256c2021-10-14 15:53:39 +020048class EF_PIN(TransparentEF):
49 def __init__(self, fid, name):
50 super().__init__(fid, name=name, desc='%s PIN file' % name)
Harald Weltec91085e2022-02-10 18:05:45 +010051
Harald Weltef44256c2021-10-14 15:53:39 +020052 def _decode_bin(self, raw_bin_data):
53 u = unpack('!BBB8s', raw_bin_data[:11])
Harald Weltec91085e2022-02-10 18:05:45 +010054 res = {'enabled': (True, False)[u[0] & 0x01],
55 'initialized': (True, False)[u[0] & 0x02],
56 'disable_able': (False, True)[u[0] & 0x10],
57 'unblock_able': (False, True)[u[0] & 0x20],
58 'change_able': (False, True)[u[0] & 0x40],
59 'valid': (False, True)[u[0] & 0x80],
60 'attempts_remaining': u[1],
61 'maximum_attempts': u[2],
62 'pin': u[3].hex(),
63 }
Harald Weltef44256c2021-10-14 15:53:39 +020064 if len(raw_bin_data) == 21:
65 u2 = unpack('!BB8s', raw_bin_data[11:10])
66 res['attempts_remaining_puk'] = u2[0]
67 res['maximum_attempts_puk'] = u2[1]
68 res['puk'] = u2[2].hex()
69 return res
70
Harald Weltec91085e2022-02-10 18:05:45 +010071
Harald Weltef44256c2021-10-14 15:53:39 +020072class EF_MILENAGE_CFG(TransparentEF):
73 def __init__(self, fid='6f21', name='EF.MILENAGE_CFG', desc='Milenage connfiguration'):
74 super().__init__(fid, name=name, desc=desc)
Harald Weltec91085e2022-02-10 18:05:45 +010075
Harald Weltef44256c2021-10-14 15:53:39 +020076 def _decode_bin(self, raw_bin_data):
77 u = unpack('!BBBBB16s16s16s16s16s', raw_bin_data)
78 return {'r1': u[0], 'r2': u[1], 'r3': u[2], 'r4': u[3], 'r5': u[4],
79 'c1': u[5].hex(),
80 'c2': u[6].hex(),
81 'c3': u[7].hex(),
82 'c4': u[8].hex(),
83 'c5': u[9].hex(),
Harald Weltec91085e2022-02-10 18:05:45 +010084 }
85
Harald Weltef44256c2021-10-14 15:53:39 +020086
87class EF_0348_KEY(LinFixedEF):
88 def __init__(self, fid='6f22', name='EF.0348_KEY', desc='TS 03.48 OTA Keys'):
Harald Welte99e4cc02022-07-21 15:25:47 +020089 super().__init__(fid, name=name, desc=desc, rec_len=(27, 35))
Harald Welte954ce952023-05-27 20:08:09 +020090 KeyLenAndType = BitStruct('mac_length'/Mapping(Bit, {8:0, 4:1}),
91 'algorithm'/Enum(Bit, des=0, aes=1),
92 'key_length'/MultiplyAdapter(BitsInteger(3), 8),
93 '_rfu'/BitsRFU(1),
94 'key_type'/Enum(BitsInteger(2), kic=0, kid=1, kik=2, any=3))
95 self._construct = Struct('security_domain'/Int8ub,
96 'key_set_version'/Int8ub,
97 'key_len_and_type'/KeyLenAndType,
98 'key'/HexAdapter(Bytes(this.key_len_and_type.key_length)))
Harald Weltec91085e2022-02-10 18:05:45 +010099
Harald Weltef44256c2021-10-14 15:53:39 +0200100
101class EF_0348_COUNT(LinFixedEF):
102 def __init__(self, fid='6f23', name='EF.0348_COUNT', desc='TS 03.48 OTA Counters'):
Harald Welte99e4cc02022-07-21 15:25:47 +0200103 super().__init__(fid, name=name, desc=desc, rec_len=(7, 7))
Harald Weltec91085e2022-02-10 18:05:45 +0100104
Harald Weltef6b37af2023-01-24 15:42:26 +0100105 def _decode_record_bin(self, raw_bin_data, **kwargs):
Harald Weltef44256c2021-10-14 15:53:39 +0200106 u = unpack('!BB5s', raw_bin_data)
107 return {'sec_domain': u[0], 'key_set_version': u[1], 'counter': u[2]}
108
Harald Weltec91085e2022-02-10 18:05:45 +0100109
Harald Weltef44256c2021-10-14 15:53:39 +0200110class EF_SIM_AUTH_COUNTER(TransparentEF):
111 def __init__(self, fid='af24', name='EF.SIM_AUTH_COUNTER'):
112 super().__init__(fid, name=name, desc='Number of remaining RUN GSM ALGORITHM executions')
113 self._construct = Struct('num_run_gsm_algo_remain'/Int32ub)
114
Harald Weltec91085e2022-02-10 18:05:45 +0100115
Harald Weltef44256c2021-10-14 15:53:39 +0200116class EF_GP_COUNT(LinFixedEF):
117 def __init__(self, fid='6f26', name='EF.GP_COUNT', desc='GP SCP02 Counters'):
Harald Welte99e4cc02022-07-21 15:25:47 +0200118 super().__init__(fid, name=name, desc=desc, rec_len=(5, 5))
Harald Weltec91085e2022-02-10 18:05:45 +0100119
Harald Weltef6b37af2023-01-24 15:42:26 +0100120 def _decode_record_bin(self, raw_bin_data, **kwargs):
Harald Weltef44256c2021-10-14 15:53:39 +0200121 u = unpack('!BBHB', raw_bin_data)
122 return {'sec_domain': u[0], 'key_set_version': u[1], 'counter': u[2], 'rfu': u[3]}
123
Harald Weltec91085e2022-02-10 18:05:45 +0100124
Harald Weltef44256c2021-10-14 15:53:39 +0200125class EF_GP_DIV_DATA(LinFixedEF):
126 def __init__(self, fid='6f27', name='EF.GP_DIV_DATA', desc='GP SCP02 key diversification data'):
Harald Welte99e4cc02022-07-21 15:25:47 +0200127 super().__init__(fid, name=name, desc=desc, rec_len=(12, 12))
Harald Weltec91085e2022-02-10 18:05:45 +0100128
Harald Weltef6b37af2023-01-24 15:42:26 +0100129 def _decode_record_bin(self, raw_bin_data, **kwargs):
Harald Weltef44256c2021-10-14 15:53:39 +0200130 u = unpack('!BB8s', raw_bin_data)
131 return {'sec_domain': u[0], 'key_set_version': u[1], 'key_div_data': u[2].hex()}
132
Harald Weltec91085e2022-02-10 18:05:45 +0100133
Harald Weltef44256c2021-10-14 15:53:39 +0200134class EF_SIM_AUTH_KEY(TransparentEF):
135 def __init__(self, fid='6f20', name='EF.SIM_AUTH_KEY'):
136 super().__init__(fid, name=name, desc='USIM authentication key')
Harald Weltecfa30152022-07-22 17:12:27 +0200137 CfgByte = BitStruct(Padding(2),
Harald Weltef44256c2021-10-14 15:53:39 +0200138 'use_sres_deriv_func_2'/Bit,
139 'use_opc_instead_of_op'/Bit,
140 'algorithm'/Enum(Nibble, milenage=4, comp128v1=1, comp128v2=2, comp128v3=3))
141 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200142 'key'/HexAdapter(Bytes(16)),
Philipp Maier4f888a02022-12-02 12:30:12 +0100143 'op_opc' /HexAdapter(Bytes(16)))
Harald Weltef44256c2021-10-14 15:53:39 +0200144
Harald Weltec91085e2022-02-10 18:05:45 +0100145
Harald Weltef44256c2021-10-14 15:53:39 +0200146class DF_SYSTEM(CardDF):
147 def __init__(self):
148 super().__init__(fid='a515', name='DF.SYSTEM', desc='CardOS specifics')
149 files = [
150 EF_PIN('6f01', 'EF.CHV1'),
151 EF_PIN('6f81', 'EF.CHV2'),
152 EF_PIN('6f0a', 'EF.ADM1'),
153 EF_PIN('6f0b', 'EF.ADM2'),
154 EF_PIN('6f0c', 'EF.ADM3'),
155 EF_PIN('6f0d', 'EF.ADM4'),
156 EF_MILENAGE_CFG(),
157 EF_0348_KEY(),
158 EF_SIM_AUTH_COUNTER(),
159 EF_SIM_AUTH_KEY(),
160 EF_0348_COUNT(),
161 EF_GP_COUNT(),
162 EF_GP_DIV_DATA(),
Harald Weltec91085e2022-02-10 18:05:45 +0100163 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200164 self.add_files(files)
165
166 def decode_select_response(self, resp_hex):
Philipp Maier5998a3a2021-11-16 15:16:39 +0100167 return pySim.ts_102_221.CardProfileUICC.decode_select_response(resp_hex)
Harald Weltef44256c2021-10-14 15:53:39 +0200168
Harald Weltec91085e2022-02-10 18:05:45 +0100169
Harald Weltef44256c2021-10-14 15:53:39 +0200170class EF_USIM_SQN(TransparentEF):
171 def __init__(self, fid='af30', name='EF.USIM_SQN'):
172 super().__init__(fid, name=name, desc='SQN parameters for AKA')
173 Flag1 = BitStruct('skip_next_sqn_check'/Bit, 'delta_max_check'/Bit,
174 'age_limit_check'/Bit, 'sqn_check'/Bit,
175 'ind_len'/BitsInteger(4))
176 Flag2 = BitStruct('rfu'/BitsRFU(5), 'dont_clear_amf_for_macs'/Bit,
177 'aus_concealed'/Bit, 'autn_concealed'/Bit)
178 self._construct = Struct('flag1'/Flag1, 'flag2'/Flag2,
Harald Weltec91085e2022-02-10 18:05:45 +0100179 'delta_max' /
180 BytesInteger(6), 'age_limit'/BytesInteger(6),
Harald Welteeb458382021-10-16 10:44:23 +0200181 'freshness'/GreedyRange(BytesInteger(6)))
Harald Weltef44256c2021-10-14 15:53:39 +0200182
Harald Weltec91085e2022-02-10 18:05:45 +0100183
Harald Weltef44256c2021-10-14 15:53:39 +0200184class EF_USIM_AUTH_KEY(TransparentEF):
185 def __init__(self, fid='af20', name='EF.USIM_AUTH_KEY'):
186 super().__init__(fid, name=name, desc='USIM authentication key')
Harald Welte03650582023-05-29 21:07:24 +0200187 Algorithm = Enum(Nibble, milenage=4, sha1_aka=5, tuak=6, xor=15)
Harald Weltecfa30152022-07-22 17:12:27 +0200188 CfgByte = BitStruct(Padding(1), 'only_4bytes_res_in_3g'/Bit,
Harald Welte03650582023-05-29 21:07:24 +0200189 'sres_deriv_func_2_in_3g'/Mapping(Bit, {1:0, 2:1}),
190 'use_opc_instead_of_op'/Mapping(Bit, {False:0, True:1}),
191 'algorithm'/Algorithm)
Harald Weltef44256c2021-10-14 15:53:39 +0200192 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200193 'key'/HexAdapter(Bytes(16)),
Philipp Maier4f888a02022-12-02 12:30:12 +0100194 'op_opc' /HexAdapter(Bytes(16)))
Harald Welte03650582023-05-29 21:07:24 +0200195 # TUAK has a rather different layout for the data, so we define a different
196 # construct below and use explicit _{decode,encode}_bin() methods for separating
197 # the TUAK and non-TUAK situation
198 CfgByteTuak = BitStruct(Padding(1),
199 'key_length'/Mapping(Bit, {128:0, 256:1}),
200 'sres_deriv_func_in_3g'/Mapping(Bit, {1:0, 2:1}),
201 'use_opc_instead_of_op'/Mapping(Bit, {False:0, True:1}),
202 'algorithm'/Algorithm)
203 TuakCfgByte = BitStruct(Padding(1),
204 'ck_and_ik_size'/Mapping(Bit, {128:0, 256:1}),
205 'mac_size'/Mapping(BitsInteger(3), {64:0, 128:1, 256:2}),
206 'res_size'/Mapping(BitsInteger(3), {32:0, 64:1, 128:2, 256:3}))
207 self._constr_tuak = Struct('cfg'/CfgByteTuak,
208 'tuak_cfg'/TuakCfgByte,
209 'num_of_keccak_iterations'/Int8ub,
210 'op_opc'/HexAdapter(Bytes(32)),
Harald Welte19b4a972023-06-08 17:18:31 +0200211 'k'/HexAdapter(Bytes(this.cfg.key_length//8)))
Harald Welte03650582023-05-29 21:07:24 +0200212
213 def _decode_bin(self, raw_bin_data: bytearray) -> dict:
214 if raw_bin_data[0] & 0x0F == 0x06:
215 return parse_construct(self._constr_tuak, raw_bin_data)
216 else:
217 return parse_construct(self._construct, raw_bin_data)
218
219 def _encode_bin(self, abstract_data: dict) -> bytearray:
220 if abstract_data['cfg']['algorithm'] == 'tuak':
221 return self._constr_tuak.build(abstract_data)
222 else:
223 return self._construct.build(abstract_data)
Harald Weltec91085e2022-02-10 18:05:45 +0100224
225
Harald Weltef44256c2021-10-14 15:53:39 +0200226class EF_USIM_AUTH_KEY_2G(TransparentEF):
227 def __init__(self, fid='af22', name='EF.USIM_AUTH_KEY_2G'):
228 super().__init__(fid, name=name, desc='USIM authentication key in 2G context')
Harald Weltecfa30152022-07-22 17:12:27 +0200229 CfgByte = BitStruct(Padding(1), 'only_4bytes_res_in_3g'/Bit,
Harald Weltef44256c2021-10-14 15:53:39 +0200230 'use_sres_deriv_func_2_in_3g'/Bit,
231 'use_opc_instead_of_op'/Bit,
Harald Welte557c1362023-05-29 15:26:22 +0200232 'algorithm'/Enum(Nibble, milenage=4, comp128v1=1, comp128v2=2, comp128v3=3, xor=14))
Harald Weltef44256c2021-10-14 15:53:39 +0200233 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200234 'key'/HexAdapter(Bytes(16)),
Philipp Maier4f888a02022-12-02 12:30:12 +0100235 'op_opc' /HexAdapter(Bytes(16)))
Harald Weltec91085e2022-02-10 18:05:45 +0100236
237
Harald Weltef44256c2021-10-14 15:53:39 +0200238class EF_GBA_SK(TransparentEF):
239 def __init__(self, fid='af31', name='EF.GBA_SK'):
240 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
241 self._construct = GreedyBytes
242
Harald Weltec91085e2022-02-10 18:05:45 +0100243
Harald Weltef44256c2021-10-14 15:53:39 +0200244class EF_GBA_REC_LIST(TransparentEF):
245 def __init__(self, fid='af32', name='EF.GBA_REC_LIST'):
246 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
247 # integers representing record numbers in EF-GBANL
248 self._construct = GreedyRange(Int8ub)
249
Harald Weltec91085e2022-02-10 18:05:45 +0100250
Harald Weltef44256c2021-10-14 15:53:39 +0200251class EF_GBA_INT_KEY(LinFixedEF):
252 def __init__(self, fid='af33', name='EF.GBA_INT_KEY'):
Harald Weltec91085e2022-02-10 18:05:45 +0100253 super().__init__(fid, name=name,
Harald Welte99e4cc02022-07-21 15:25:47 +0200254 desc='Secret key for GBA key derivation', rec_len=(32, 32))
Harald Weltef44256c2021-10-14 15:53:39 +0200255 self._construct = GreedyBytes
256
257
Harald Weltef44256c2021-10-14 15:53:39 +0200258class SysmocomSJA2(CardModel):
Harald Weltec91085e2022-02-10 18:05:45 +0100259 _atrs = ["3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9",
260 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2",
261 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"]
262
Harald Weltef44256c2021-10-14 15:53:39 +0200263 @classmethod
Harald Weltec91085e2022-02-10 18:05:45 +0100264 def add_files(cls, rs: RuntimeState):
Harald Weltef44256c2021-10-14 15:53:39 +0200265 """Add sysmocom SJA2 specific files to given RuntimeState."""
266 rs.mf.add_file(DF_SYSTEM())
267 # optional USIM application
268 if 'a0000000871002' in rs.mf.applications:
269 usim_adf = rs.mf.applications['a0000000871002']
270 files_adf_usim = [
271 EF_USIM_AUTH_KEY(),
272 EF_USIM_AUTH_KEY_2G(),
273 EF_GBA_SK(),
274 EF_GBA_REC_LIST(),
275 EF_GBA_INT_KEY(),
276 EF_USIM_SQN(),
Harald Weltec91085e2022-02-10 18:05:45 +0100277 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200278 usim_adf.add_files(files_adf_usim)
279 # optional ISIM application
280 if 'a0000000871004' in rs.mf.applications:
281 isim_adf = rs.mf.applications['a0000000871004']
282 files_adf_isim = [
283 EF_USIM_AUTH_KEY(name='EF.ISIM_AUTH_KEY'),
284 EF_USIM_AUTH_KEY_2G(name='EF.ISIM_AUTH_KEY_2G'),
285 EF_USIM_SQN(name='EF.ISIM_SQN'),
Harald Weltec91085e2022-02-10 18:05:45 +0100286 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200287 isim_adf.add_files(files_adf_isim)
Harald Welte0489ae62023-05-24 10:28:34 +0200288
289class SysmocomSJA5(CardModel):
290 _atrs = ["3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 51 CC",
291 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 65 F8",
292 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 59 C4"]
293
294 @classmethod
295 def add_files(cls, rs: RuntimeState):
296 """Add sysmocom SJA2 specific files to given RuntimeState."""
297 rs.mf.add_file(DF_SYSTEM())
298 # optional USIM application
299 if 'a0000000871002' in rs.mf.applications:
300 usim_adf = rs.mf.applications['a0000000871002']
301 files_adf_usim = [
302 EF_USIM_AUTH_KEY(),
303 EF_USIM_AUTH_KEY_2G(),
304 EF_GBA_SK(),
305 EF_GBA_REC_LIST(),
306 EF_GBA_INT_KEY(),
307 EF_USIM_SQN(),
308 ]
309 usim_adf.add_files(files_adf_usim)
310 # optional ISIM application
311 if 'a0000000871004' in rs.mf.applications:
312 isim_adf = rs.mf.applications['a0000000871004']
313 files_adf_isim = [
314 EF_USIM_AUTH_KEY(name='EF.ISIM_AUTH_KEY'),
315 EF_USIM_AUTH_KEY_2G(name='EF.ISIM_AUTH_KEY_2G'),
316 EF_USIM_SQN(name='EF.ISIM_SQN'),
317 ]
318 isim_adf.add_files(files_adf_isim)