blob: 53e6585c95597e58c70ca57d2cb71f553b6eb4ef [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 Welte99e4cc02022-07-21 15:25:47 +020088 super().__init__(fid, name=name, desc=desc, rec_len=(27, 35))
Harald Weltec91085e2022-02-10 18:05:45 +010089
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 Welte99e4cc02022-07-21 15:25:47 +0200106 super().__init__(fid, name=name, desc=desc, rec_len=(7, 7))
Harald Weltec91085e2022-02-10 18:05:45 +0100107
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 Welte99e4cc02022-07-21 15:25:47 +0200121 super().__init__(fid, name=name, desc=desc, rec_len=(5, 5))
Harald Weltec91085e2022-02-10 18:05:45 +0100122
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 Welte99e4cc02022-07-21 15:25:47 +0200130 super().__init__(fid, name=name, desc=desc, rec_len=(12, 12))
Harald Weltec91085e2022-02-10 18:05:45 +0100131
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')
Harald Weltecfa30152022-07-22 17:12:27 +0200140 CfgByte = BitStruct(Padding(2),
Harald Weltef44256c2021-10-14 15:53:39 +0200141 '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,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200145 'key'/HexAdapter(Bytes(16)),
146 'op'/ If(this.cfg.algorithm == 'milenage' and not this.cfg.use_opc_instead_of_op,
147 HexAdapter(Bytes(16))),
Harald Weltec91085e2022-02-10 18:05:45 +0100148 'opc' /
Harald Welte3c98d5e2022-07-20 07:40:05 +0200149 If(this.cfg.algorithm == 'milenage' and this.cfg.use_opc_instead_of_op,
150 HexAdapter(Bytes(16)))
Harald Weltef44256c2021-10-14 15:53:39 +0200151 )
152
Harald Weltec91085e2022-02-10 18:05:45 +0100153
Harald Weltef44256c2021-10-14 15:53:39 +0200154class DF_SYSTEM(CardDF):
155 def __init__(self):
156 super().__init__(fid='a515', name='DF.SYSTEM', desc='CardOS specifics')
157 files = [
158 EF_PIN('6f01', 'EF.CHV1'),
159 EF_PIN('6f81', 'EF.CHV2'),
160 EF_PIN('6f0a', 'EF.ADM1'),
161 EF_PIN('6f0b', 'EF.ADM2'),
162 EF_PIN('6f0c', 'EF.ADM3'),
163 EF_PIN('6f0d', 'EF.ADM4'),
164 EF_MILENAGE_CFG(),
165 EF_0348_KEY(),
166 EF_SIM_AUTH_COUNTER(),
167 EF_SIM_AUTH_KEY(),
168 EF_0348_COUNT(),
169 EF_GP_COUNT(),
170 EF_GP_DIV_DATA(),
Harald Weltec91085e2022-02-10 18:05:45 +0100171 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200172 self.add_files(files)
173
174 def decode_select_response(self, resp_hex):
Philipp Maier5998a3a2021-11-16 15:16:39 +0100175 return pySim.ts_102_221.CardProfileUICC.decode_select_response(resp_hex)
Harald Weltef44256c2021-10-14 15:53:39 +0200176
Harald Weltec91085e2022-02-10 18:05:45 +0100177
Harald Weltef44256c2021-10-14 15:53:39 +0200178class EF_USIM_SQN(TransparentEF):
179 def __init__(self, fid='af30', name='EF.USIM_SQN'):
180 super().__init__(fid, name=name, desc='SQN parameters for AKA')
181 Flag1 = BitStruct('skip_next_sqn_check'/Bit, 'delta_max_check'/Bit,
182 'age_limit_check'/Bit, 'sqn_check'/Bit,
183 'ind_len'/BitsInteger(4))
184 Flag2 = BitStruct('rfu'/BitsRFU(5), 'dont_clear_amf_for_macs'/Bit,
185 'aus_concealed'/Bit, 'autn_concealed'/Bit)
186 self._construct = Struct('flag1'/Flag1, 'flag2'/Flag2,
Harald Weltec91085e2022-02-10 18:05:45 +0100187 'delta_max' /
188 BytesInteger(6), 'age_limit'/BytesInteger(6),
Harald Welteeb458382021-10-16 10:44:23 +0200189 'freshness'/GreedyRange(BytesInteger(6)))
Harald Weltef44256c2021-10-14 15:53:39 +0200190
Harald Weltec91085e2022-02-10 18:05:45 +0100191
Harald Weltef44256c2021-10-14 15:53:39 +0200192class EF_USIM_AUTH_KEY(TransparentEF):
193 def __init__(self, fid='af20', name='EF.USIM_AUTH_KEY'):
194 super().__init__(fid, name=name, desc='USIM authentication key')
Harald Weltecfa30152022-07-22 17:12:27 +0200195 CfgByte = BitStruct(Padding(1), 'only_4bytes_res_in_3g'/Bit,
Harald Weltef44256c2021-10-14 15:53:39 +0200196 'use_sres_deriv_func_2_in_3g'/Bit,
197 'use_opc_instead_of_op'/Bit,
198 'algorithm'/Enum(Nibble, milenage=4, sha1_aka=5, xor=15))
199 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200200 'key'/HexAdapter(Bytes(16)),
Harald Weltec91085e2022-02-10 18:05:45 +0100201 'op' /
Harald Welte3c98d5e2022-07-20 07:40:05 +0200202 If(this.cfg.algorithm == 'milenage' and not this.cfg.use_opc_instead_of_op,
203 HexAdapter(Bytes(16))),
Harald Weltec91085e2022-02-10 18:05:45 +0100204 'opc' /
Harald Welte3c98d5e2022-07-20 07:40:05 +0200205 If(this.cfg.algorithm == 'milenage' and this.cfg.use_opc_instead_of_op,
206 HexAdapter(Bytes(16)))
Harald Weltef44256c2021-10-14 15:53:39 +0200207 )
Harald Weltec91085e2022-02-10 18:05:45 +0100208
209
Harald Weltef44256c2021-10-14 15:53:39 +0200210class EF_USIM_AUTH_KEY_2G(TransparentEF):
211 def __init__(self, fid='af22', name='EF.USIM_AUTH_KEY_2G'):
212 super().__init__(fid, name=name, desc='USIM authentication key in 2G context')
Harald Weltecfa30152022-07-22 17:12:27 +0200213 CfgByte = BitStruct(Padding(1), 'only_4bytes_res_in_3g'/Bit,
Harald Weltef44256c2021-10-14 15:53:39 +0200214 'use_sres_deriv_func_2_in_3g'/Bit,
215 'use_opc_instead_of_op'/Bit,
216 'algorithm'/Enum(Nibble, milenage=4, comp128v1=1, comp128v2=2, comp128v3=3))
217 self._construct = Struct('cfg'/CfgByte,
Harald Welte3c98d5e2022-07-20 07:40:05 +0200218 'key'/HexAdapter(Bytes(16)),
Harald Weltec91085e2022-02-10 18:05:45 +0100219 'op' /
Harald Welte3c98d5e2022-07-20 07:40:05 +0200220 If(this.cfg.algorithm == 'milenage' and not this.cfg.use_opc_instead_of_op,
221 HexAdapter(Bytes(16))),
Harald Weltec91085e2022-02-10 18:05:45 +0100222 'opc' /
Harald Welte3c98d5e2022-07-20 07:40:05 +0200223 If(this.cfg.algorithm == 'milenage' and this.cfg.use_opc_instead_of_op,
224 HexAdapter(Bytes(16)))
Harald Weltef44256c2021-10-14 15:53:39 +0200225 )
Harald Weltec91085e2022-02-10 18:05:45 +0100226
227
Harald Weltef44256c2021-10-14 15:53:39 +0200228class EF_GBA_SK(TransparentEF):
229 def __init__(self, fid='af31', name='EF.GBA_SK'):
230 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
231 self._construct = GreedyBytes
232
Harald Weltec91085e2022-02-10 18:05:45 +0100233
Harald Weltef44256c2021-10-14 15:53:39 +0200234class EF_GBA_REC_LIST(TransparentEF):
235 def __init__(self, fid='af32', name='EF.GBA_REC_LIST'):
236 super().__init__(fid, name=name, desc='Secret key for GBA key derivation')
237 # integers representing record numbers in EF-GBANL
238 self._construct = GreedyRange(Int8ub)
239
Harald Weltec91085e2022-02-10 18:05:45 +0100240
Harald Weltef44256c2021-10-14 15:53:39 +0200241class EF_GBA_INT_KEY(LinFixedEF):
242 def __init__(self, fid='af33', name='EF.GBA_INT_KEY'):
Harald Weltec91085e2022-02-10 18:05:45 +0100243 super().__init__(fid, name=name,
Harald Welte99e4cc02022-07-21 15:25:47 +0200244 desc='Secret key for GBA key derivation', rec_len=(32, 32))
Harald Weltef44256c2021-10-14 15:53:39 +0200245 self._construct = GreedyBytes
246
247
Harald Weltef44256c2021-10-14 15:53:39 +0200248class SysmocomSJA2(CardModel):
Harald Weltec91085e2022-02-10 18:05:45 +0100249 _atrs = ["3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 30 34 05 4B A9",
250 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 75 31 33 02 51 B2",
251 "3B 9F 96 80 1F 87 80 31 E0 73 FE 21 1B 67 4A 4C 52 75 31 04 51 D5"]
252
Harald Weltef44256c2021-10-14 15:53:39 +0200253 @classmethod
Harald Weltec91085e2022-02-10 18:05:45 +0100254 def add_files(cls, rs: RuntimeState):
Harald Weltef44256c2021-10-14 15:53:39 +0200255 """Add sysmocom SJA2 specific files to given RuntimeState."""
256 rs.mf.add_file(DF_SYSTEM())
257 # optional USIM application
258 if 'a0000000871002' in rs.mf.applications:
259 usim_adf = rs.mf.applications['a0000000871002']
260 files_adf_usim = [
261 EF_USIM_AUTH_KEY(),
262 EF_USIM_AUTH_KEY_2G(),
263 EF_GBA_SK(),
264 EF_GBA_REC_LIST(),
265 EF_GBA_INT_KEY(),
266 EF_USIM_SQN(),
Harald Weltec91085e2022-02-10 18:05:45 +0100267 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200268 usim_adf.add_files(files_adf_usim)
269 # optional ISIM application
270 if 'a0000000871004' in rs.mf.applications:
271 isim_adf = rs.mf.applications['a0000000871004']
272 files_adf_isim = [
273 EF_USIM_AUTH_KEY(name='EF.ISIM_AUTH_KEY'),
274 EF_USIM_AUTH_KEY_2G(name='EF.ISIM_AUTH_KEY_2G'),
275 EF_USIM_SQN(name='EF.ISIM_SQN'),
Harald Weltec91085e2022-02-10 18:05:45 +0100276 ]
Harald Weltef44256c2021-10-14 15:53:39 +0200277 isim_adf.add_files(files_adf_isim)