blob: 8b1fc04ed1a5acc60487186aaf3a44b906773a27 [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 *
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 Welte99e4cc02022-07-21 15:25:47 +020088 super().__init__(fid, name=name, desc=desc, rec_len=(27, 35))
Harald Welte954ce952023-05-27 20:08:09 +020089 KeyLenAndType = BitStruct('mac_length'/Mapping(Bit, {8:0, 4:1}),
90 'algorithm'/Enum(Bit, des=0, aes=1),
91 'key_length'/MultiplyAdapter(BitsInteger(3), 8),
92 '_rfu'/BitsRFU(1),
93 'key_type'/Enum(BitsInteger(2), kic=0, kid=1, kik=2, any=3))
94 self._construct = Struct('security_domain'/Int8ub,
95 'key_set_version'/Int8ub,
96 'key_len_and_type'/KeyLenAndType,
97 'key'/HexAdapter(Bytes(this.key_len_and_type.key_length)))
Harald Weltec91085e2022-02-10 18:05:45 +010098
Harald Weltef44256c2021-10-14 15:53:39 +020099
100class EF_0348_COUNT(LinFixedEF):
101 def __init__(self, fid='6f23', name='EF.0348_COUNT', desc='TS 03.48 OTA Counters'):
Harald Welte99e4cc02022-07-21 15:25:47 +0200102 super().__init__(fid, name=name, desc=desc, rec_len=(7, 7))
Harald Weltec91085e2022-02-10 18:05:45 +0100103
Harald Weltef6b37af2023-01-24 15:42:26 +0100104 def _decode_record_bin(self, raw_bin_data, **kwargs):
Harald Weltef44256c2021-10-14 15:53:39 +0200105 u = unpack('!BB5s', raw_bin_data)
106 return {'sec_domain': u[0], 'key_set_version': u[1], 'counter': u[2]}
107
Harald Weltec91085e2022-02-10 18:05:45 +0100108
Harald Weltef44256c2021-10-14 15:53:39 +0200109class EF_SIM_AUTH_COUNTER(TransparentEF):
110 def __init__(self, fid='af24', name='EF.SIM_AUTH_COUNTER'):
111 super().__init__(fid, name=name, desc='Number of remaining RUN GSM ALGORITHM executions')
112 self._construct = Struct('num_run_gsm_algo_remain'/Int32ub)
113
Harald Weltec91085e2022-02-10 18:05:45 +0100114
Harald Weltef44256c2021-10-14 15:53:39 +0200115class EF_GP_COUNT(LinFixedEF):
116 def __init__(self, fid='6f26', name='EF.GP_COUNT', desc='GP SCP02 Counters'):
Harald Welte99e4cc02022-07-21 15:25:47 +0200117 super().__init__(fid, name=name, desc=desc, rec_len=(5, 5))
Harald Weltec91085e2022-02-10 18:05:45 +0100118
Harald Weltef6b37af2023-01-24 15:42:26 +0100119 def _decode_record_bin(self, raw_bin_data, **kwargs):
Harald Weltef44256c2021-10-14 15:53:39 +0200120 u = unpack('!BBHB', raw_bin_data)
121 return {'sec_domain': u[0], 'key_set_version': u[1], 'counter': u[2], 'rfu': u[3]}
122
Harald Weltec91085e2022-02-10 18:05:45 +0100123
Harald Weltef44256c2021-10-14 15:53:39 +0200124class EF_GP_DIV_DATA(LinFixedEF):
125 def __init__(self, fid='6f27', name='EF.GP_DIV_DATA', desc='GP SCP02 key diversification data'):
Harald Welte99e4cc02022-07-21 15:25:47 +0200126 super().__init__(fid, name=name, desc=desc, rec_len=(12, 12))
Harald Weltec91085e2022-02-10 18:05:45 +0100127
Harald Weltef6b37af2023-01-24 15:42:26 +0100128 def _decode_record_bin(self, raw_bin_data, **kwargs):
Harald Weltef44256c2021-10-14 15:53:39 +0200129 u = unpack('!BB8s', raw_bin_data)
130 return {'sec_domain': u[0], 'key_set_version': u[1], 'key_div_data': u[2].hex()}
131
Harald Weltec91085e2022-02-10 18:05:45 +0100132
Harald Weltef44256c2021-10-14 15:53:39 +0200133class EF_SIM_AUTH_KEY(TransparentEF):
134 def __init__(self, fid='6f20', name='EF.SIM_AUTH_KEY'):
135 super().__init__(fid, name=name, desc='USIM authentication key')
Harald Weltecfa30152022-07-22 17:12:27 +0200136 CfgByte = BitStruct(Padding(2),
Harald Weltef44256c2021-10-14 15:53:39 +0200137 'use_sres_deriv_func_2'/Bit,
138 'use_opc_instead_of_op'/Bit,
139 'algorithm'/Enum(Nibble, milenage=4, comp128v1=1, comp128v2=2, comp128v3=3))
140 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200141 'key'/HexAdapter(Bytes(16)),
Philipp Maier4f888a02022-12-02 12:30:12 +0100142 'op_opc' /HexAdapter(Bytes(16)))
Harald Weltef44256c2021-10-14 15:53:39 +0200143
Harald Weltec91085e2022-02-10 18:05:45 +0100144
Harald Weltef44256c2021-10-14 15:53:39 +0200145class DF_SYSTEM(CardDF):
146 def __init__(self):
147 super().__init__(fid='a515', name='DF.SYSTEM', desc='CardOS specifics')
148 files = [
149 EF_PIN('6f01', 'EF.CHV1'),
150 EF_PIN('6f81', 'EF.CHV2'),
151 EF_PIN('6f0a', 'EF.ADM1'),
152 EF_PIN('6f0b', 'EF.ADM2'),
153 EF_PIN('6f0c', 'EF.ADM3'),
154 EF_PIN('6f0d', 'EF.ADM4'),
155 EF_MILENAGE_CFG(),
156 EF_0348_KEY(),
157 EF_SIM_AUTH_COUNTER(),
158 EF_SIM_AUTH_KEY(),
159 EF_0348_COUNT(),
160 EF_GP_COUNT(),
161 EF_GP_DIV_DATA(),
Harald Weltec91085e2022-02-10 18:05:45 +0100162 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200163 self.add_files(files)
164
165 def decode_select_response(self, resp_hex):
Philipp Maier5998a3a2021-11-16 15:16:39 +0100166 return pySim.ts_102_221.CardProfileUICC.decode_select_response(resp_hex)
Harald Weltef44256c2021-10-14 15:53:39 +0200167
Harald Weltec91085e2022-02-10 18:05:45 +0100168
Harald Weltef44256c2021-10-14 15:53:39 +0200169class EF_USIM_SQN(TransparentEF):
170 def __init__(self, fid='af30', name='EF.USIM_SQN'):
171 super().__init__(fid, name=name, desc='SQN parameters for AKA')
172 Flag1 = BitStruct('skip_next_sqn_check'/Bit, 'delta_max_check'/Bit,
173 'age_limit_check'/Bit, 'sqn_check'/Bit,
174 'ind_len'/BitsInteger(4))
175 Flag2 = BitStruct('rfu'/BitsRFU(5), 'dont_clear_amf_for_macs'/Bit,
176 'aus_concealed'/Bit, 'autn_concealed'/Bit)
177 self._construct = Struct('flag1'/Flag1, 'flag2'/Flag2,
Harald Weltec91085e2022-02-10 18:05:45 +0100178 'delta_max' /
179 BytesInteger(6), 'age_limit'/BytesInteger(6),
Harald Welteeb458382021-10-16 10:44:23 +0200180 'freshness'/GreedyRange(BytesInteger(6)))
Harald Weltef44256c2021-10-14 15:53:39 +0200181
Harald Weltec91085e2022-02-10 18:05:45 +0100182
Harald Weltef44256c2021-10-14 15:53:39 +0200183class EF_USIM_AUTH_KEY(TransparentEF):
184 def __init__(self, fid='af20', name='EF.USIM_AUTH_KEY'):
185 super().__init__(fid, name=name, desc='USIM authentication key')
Harald Welte03650582023-05-29 21:07:24 +0200186 Algorithm = Enum(Nibble, milenage=4, sha1_aka=5, tuak=6, xor=15)
Harald Weltecfa30152022-07-22 17:12:27 +0200187 CfgByte = BitStruct(Padding(1), 'only_4bytes_res_in_3g'/Bit,
Harald Welte03650582023-05-29 21:07:24 +0200188 'sres_deriv_func_2_in_3g'/Mapping(Bit, {1:0, 2:1}),
189 'use_opc_instead_of_op'/Mapping(Bit, {False:0, True:1}),
190 'algorithm'/Algorithm)
Harald Weltef44256c2021-10-14 15:53:39 +0200191 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200192 'key'/HexAdapter(Bytes(16)),
Philipp Maier4f888a02022-12-02 12:30:12 +0100193 'op_opc' /HexAdapter(Bytes(16)))
Harald Welte03650582023-05-29 21:07:24 +0200194 # TUAK has a rather different layout for the data, so we define a different
195 # construct below and use explicit _{decode,encode}_bin() methods for separating
196 # the TUAK and non-TUAK situation
197 CfgByteTuak = BitStruct(Padding(1),
198 'key_length'/Mapping(Bit, {128:0, 256:1}),
199 'sres_deriv_func_in_3g'/Mapping(Bit, {1:0, 2:1}),
200 'use_opc_instead_of_op'/Mapping(Bit, {False:0, True:1}),
201 'algorithm'/Algorithm)
202 TuakCfgByte = BitStruct(Padding(1),
203 'ck_and_ik_size'/Mapping(Bit, {128:0, 256:1}),
204 'mac_size'/Mapping(BitsInteger(3), {64:0, 128:1, 256:2}),
205 'res_size'/Mapping(BitsInteger(3), {32:0, 64:1, 128:2, 256:3}))
206 self._constr_tuak = Struct('cfg'/CfgByteTuak,
207 'tuak_cfg'/TuakCfgByte,
208 'num_of_keccak_iterations'/Int8ub,
209 'op_opc'/HexAdapter(Bytes(32)),
210 'k'/HexAdapter(Bytes(32)))
211
212 def _decode_bin(self, raw_bin_data: bytearray) -> dict:
213 if raw_bin_data[0] & 0x0F == 0x06:
214 return parse_construct(self._constr_tuak, raw_bin_data)
215 else:
216 return parse_construct(self._construct, raw_bin_data)
217
218 def _encode_bin(self, abstract_data: dict) -> bytearray:
219 if abstract_data['cfg']['algorithm'] == 'tuak':
220 return self._constr_tuak.build(abstract_data)
221 else:
222 return self._construct.build(abstract_data)
Harald Weltec91085e2022-02-10 18:05:45 +0100223
224
Harald Weltef44256c2021-10-14 15:53:39 +0200225class EF_USIM_AUTH_KEY_2G(TransparentEF):
226 def __init__(self, fid='af22', name='EF.USIM_AUTH_KEY_2G'):
227 super().__init__(fid, name=name, desc='USIM authentication key in 2G context')
Harald Weltecfa30152022-07-22 17:12:27 +0200228 CfgByte = BitStruct(Padding(1), 'only_4bytes_res_in_3g'/Bit,
Harald Weltef44256c2021-10-14 15:53:39 +0200229 'use_sres_deriv_func_2_in_3g'/Bit,
230 'use_opc_instead_of_op'/Bit,
Harald Welte557c1362023-05-29 15:26:22 +0200231 'algorithm'/Enum(Nibble, milenage=4, comp128v1=1, comp128v2=2, comp128v3=3, xor=14))
Harald Weltef44256c2021-10-14 15:53:39 +0200232 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200233 'key'/HexAdapter(Bytes(16)),
Philipp Maier4f888a02022-12-02 12:30:12 +0100234 'op_opc' /HexAdapter(Bytes(16)))
Harald Weltec91085e2022-02-10 18:05:45 +0100235
236
Harald Weltef44256c2021-10-14 15:53:39 +0200237class EF_GBA_SK(TransparentEF):
238 def __init__(self, fid='af31', name='EF.GBA_SK'):
239 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
240 self._construct = GreedyBytes
241
Harald Weltec91085e2022-02-10 18:05:45 +0100242
Harald Weltef44256c2021-10-14 15:53:39 +0200243class EF_GBA_REC_LIST(TransparentEF):
244 def __init__(self, fid='af32', name='EF.GBA_REC_LIST'):
245 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
246 # integers representing record numbers in EF-GBANL
247 self._construct = GreedyRange(Int8ub)
248
Harald Weltec91085e2022-02-10 18:05:45 +0100249
Harald Weltef44256c2021-10-14 15:53:39 +0200250class EF_GBA_INT_KEY(LinFixedEF):
251 def __init__(self, fid='af33', name='EF.GBA_INT_KEY'):
Harald Weltec91085e2022-02-10 18:05:45 +0100252 super().__init__(fid, name=name,
Harald Welte99e4cc02022-07-21 15:25:47 +0200253 desc='Secret key for GBA key derivation', rec_len=(32, 32))
Harald Weltef44256c2021-10-14 15:53:39 +0200254 self._construct = GreedyBytes
255
256
Harald Weltef44256c2021-10-14 15:53:39 +0200257class SysmocomSJA2(CardModel):
Harald Weltec91085e2022-02-10 18:05:45 +0100258 _atrs = ["3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9",
259 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2",
260 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"]
261
Harald Weltef44256c2021-10-14 15:53:39 +0200262 @classmethod
Harald Weltec91085e2022-02-10 18:05:45 +0100263 def add_files(cls, rs: RuntimeState):
Harald Weltef44256c2021-10-14 15:53:39 +0200264 """Add sysmocom SJA2 specific files to given RuntimeState."""
265 rs.mf.add_file(DF_SYSTEM())
266 # optional USIM application
267 if 'a0000000871002' in rs.mf.applications:
268 usim_adf = rs.mf.applications['a0000000871002']
269 files_adf_usim = [
270 EF_USIM_AUTH_KEY(),
271 EF_USIM_AUTH_KEY_2G(),
272 EF_GBA_SK(),
273 EF_GBA_REC_LIST(),
274 EF_GBA_INT_KEY(),
275 EF_USIM_SQN(),
Harald Weltec91085e2022-02-10 18:05:45 +0100276 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200277 usim_adf.add_files(files_adf_usim)
278 # optional ISIM application
279 if 'a0000000871004' in rs.mf.applications:
280 isim_adf = rs.mf.applications['a0000000871004']
281 files_adf_isim = [
282 EF_USIM_AUTH_KEY(name='EF.ISIM_AUTH_KEY'),
283 EF_USIM_AUTH_KEY_2G(name='EF.ISIM_AUTH_KEY_2G'),
284 EF_USIM_SQN(name='EF.ISIM_SQN'),
Harald Weltec91085e2022-02-10 18:05:45 +0100285 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200286 isim_adf.add_files(files_adf_isim)
Harald Welte0489ae62023-05-24 10:28:34 +0200287
288class SysmocomSJA5(CardModel):
289 _atrs = ["3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 51 CC",
290 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 65 F8",
291 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 35 75 30 35 02 59 C4"]
292
293 @classmethod
294 def add_files(cls, rs: RuntimeState):
295 """Add sysmocom SJA2 specific files to given RuntimeState."""
296 rs.mf.add_file(DF_SYSTEM())
297 # optional USIM application
298 if 'a0000000871002' in rs.mf.applications:
299 usim_adf = rs.mf.applications['a0000000871002']
300 files_adf_usim = [
301 EF_USIM_AUTH_KEY(),
302 EF_USIM_AUTH_KEY_2G(),
303 EF_GBA_SK(),
304 EF_GBA_REC_LIST(),
305 EF_GBA_INT_KEY(),
306 EF_USIM_SQN(),
307 ]
308 usim_adf.add_files(files_adf_usim)
309 # optional ISIM application
310 if 'a0000000871004' in rs.mf.applications:
311 isim_adf = rs.mf.applications['a0000000871004']
312 files_adf_isim = [
313 EF_USIM_AUTH_KEY(name='EF.ISIM_AUTH_KEY'),
314 EF_USIM_AUTH_KEY_2G(name='EF.ISIM_AUTH_KEY_2G'),
315 EF_USIM_SQN(name='EF.ISIM_SQN'),
316 ]
317 isim_adf.add_files(files_adf_isim)