blob: c3e18d820ddb7cf9b25e7d2c9499d8ba53ff64e6 [file] [log] [blame]
Harald Welte4acaa132016-03-14 15:35:50 +01001/* simtrace - tables determining APDU case for card emulation
2 *
3 * (C) 2016 by Harald Welte <laforge@gnumonks.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2, or
7 * any later version as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include <stdint.h>
20#include <osmocom/core/utils.h>
21#include <osmocom/sim/class_tables.h>
22
23static const uint8_t iso7816_ins_tbl[] = {
24 [0xB0] = 2, /* READ BIN */
25 [0xD0] = 3, /* WRITE BIN */
26 [0xD6] = 3, /* UPDATE BIN */
27 [0x0E] = 3, /* ERASE BIN */
28 [0xB2] = 2, /* READ REC */
29 [0xD2] = 3, /* WRITE REC */
30 [0xE2] = 3, /* APPEND REC */
31 [0xDC] = 3, /* UPDATE REC */
32 [0xCA] = 2, /* GET DATA */
33 [0xDA] = 3, /* PUT DATA */
34 [0xA4] = 4, /* SELECT FILE */
35 [0x20] = 3, /* VERIFY */
36 [0x88] = 4, /* INT AUTH */
37 [0x82] = 3, /* EXT AUTH */
38 [0x84] = 2, /* GET CHALLENGE */
39 [0x70] = 2, /* MANAGE CHANNEL */
40};
41
42static const struct osim_cla_ins_case iso7816_4_ins_case[] = {
43 {
44 .cla = 0x00,
45 .cla_mask = 0xF0,
46 .ins_tbl = iso7816_ins_tbl,
47 }, {
48 .cla = 0x80, /* 0x80/0x90 */
49 .cla_mask = 0xE0,
50 .ins_tbl = iso7816_ins_tbl,
51 }, {
52 .cla = 0xB0,
53 .cla_mask = 0xF0,
54 .ins_tbl = iso7816_ins_tbl,
55 }, {
56 .cla = 0xC0,
57 .cla_mask = 0xF0,
58 .ins_tbl = iso7816_ins_tbl,
59 },
60};
61
62const struct osim_cla_ins_card_profile osim_iso7816_cic_profile = {
63 .name = "ISO 7816-4",
64 .description = "ISO 7816-4",
65 .cic_arr = iso7816_4_ins_case,
66 .cic_arr_size = ARRAY_SIZE(iso7816_4_ins_case),
67};
68
69static const uint8_t gsm1111_ins_tbl[256] = {
70 [0xA4] = 4, /* SELECT FILE */
71 [0xF2] = 2, /* STATUS */
72 [0xB0] = 2, /* READ BINARY */
73 [0xD6] = 3, /* UPDATE BINARY */
74 [0xB2] = 2, /* READ RECORD */
75 [0xDC] = 3, /* UPDATE RECORD */
76 [0xA2] = 4, /* SEEK */
77 [0x32] = 4, /* INCREASE */
78 [0x20] = 3, /* VERIFY CHV */
79 [0x24] = 3, /* CHANGE CHV */
80 [0x26] = 3, /* DISABLE CHV */
81 [0x28] = 3, /* ENABLE CHV */
82 [0x2C] = 3, /* UNBLOCK CHV */
83 [0x04] = 1, /* INVALIDATE */
84 [0x44] = 1, /* REHABILITATE */
85 [0x88] = 4, /* RUN GSM ALGO */
86 [0xFA] = 1, /* SLEEP */
87 [0xC0] = 2, /* GET RESPONSE */
88 [0x10] = 3, /* TERMINAL PROFILE */
89 [0xC2] = 4, /* ENVELOPE */
90 [0x12] = 2, /* FETCH */
91 [0x14] = 3, /* TERMINAL RESPONSE */
92};
93
94/* According to Table 9 / Section 9.2 of TS 11.11 */
95static const struct osim_cla_ins_case gsm1111_ins_case[] = {
96 {
97 .cla = 0xA0,
98 .cla_mask = 0xFF,
99 .ins_tbl = gsm1111_ins_tbl,
100 },
101};
102
103const struct osim_cla_ins_card_profile osim_gsm1111_cic_profile = {
104 .name = "GSM SIM",
105 .description = "GSM/3GPP TS 11.11",
106 .cic_arr = gsm1111_ins_case,
107 .cic_arr_size = ARRAY_SIZE(gsm1111_ins_case),
108};
109
110/* ETSI TS 102 221, Table 10.5, CLA = 0x0x, 0x4x or 0x6x */
111static const uint8_t uicc_ins_tbl_046[256] = {
112 [0xA4] = 4, /* SELET FILE */
113 [0xB0] = 2, /* READ BINARY */
114 [0xD6] = 3, /* UPDATE BINARY */
115 [0xB2] = 2, /* READ RECORD */
116 [0xDC] = 3, /* UPDATE RECORD */
117 [0xA2] = 4, /* SEEK */
118 [0x20] = 3, /* VERIFY PIN */
119 [0x24] = 3, /* CHANGE PIN */
120 [0x26] = 3, /* DISABLE PIN */
121 [0x28] = 3, /* ENABLE PIN */
122 [0x2C] = 3, /* UNBLOCK PIN */
123 [0x04] = 1, /* DEACTIVATE FILE */
124 [0x44] = 1, /* ACTIVATE FILE */
125 [0x88] = 4, /* AUTHENTICATE */
126 [0x89] = 4, /* AUTHENTICATE */
127 [0x84] = 2, /* GET CHALLENGE */
128 [0x70] = 2, /* MANAGE CHANNEL */
129 [0x73] = 0x80, /* MANAGE SECURE CHANNEL */
130 [0x75] = 0x80, /* TRANSACT DATA */
131 [0xC0] = 2, /* GET RESPONSE */
132};
133
134static int uicc046_cla_ins_helper(const struct osim_cla_ins_case *cic,
135 const uint8_t *hdr)
136{
137 uint8_t ins = hdr[1];
138 uint8_t p1 = hdr[2];
139 uint8_t p2 = hdr[3];
140 uint8_t p2_cmd;
141
142 switch (ins) {
143 case 0x73: /* MANAGE SECURE CHANNEL */
144 if (p1 == 0x00) /* Retrieve UICC Endpoints */
145 return 2;
146 switch (p1 & 0x07) {
147 case 1: /* Establish SA - Master SA */
148 case 2: /* Establish SA - Conn. SA */
149 case 3: /* Start secure channel SA */
150 p2_cmd = p2 >> 5;
151 if (p2 == 0x80 || p2_cmd == 0) {
152 /* command data */
153 return 3;
154 }
155 if (p2_cmd == 5 || p2_cmd == 1) {
156 /* response data */
157 return 2;
158 }
159 return 0;
160 break;
161 case 4: /* Terminate secure chan SA */
162 return 3;
163 break;
164 }
165 break;
166 case 0x75: /* TRANSACT DATA */
167 if (p1 & 0x04)
168 return 3;
169 else
170 return 2;
171 break;
172 }
173
174 return 0;
175}
176
177/* ETSI TS 102 221, Table 10.5, CLA = 0x8x, 0xCx or 0xEx */
178static const uint8_t uicc_ins_tbl_8ce[256] = {
179 [0xF2] = 2, /* STATUS */
180 [0x32] = 4, /* INCREASE */
181 [0xCB] = 4, /* RETRIEVE DATA */
182 [0xDB] = 3, /* SET DATA */
183 [0xAA] = 3, /* TERMINAL CAPABILITY */
184};
185
186/* ETSI TS 102 221, Table 10.5, CLA = 0x80 */
187static const uint8_t uicc_ins_tbl_80[256] = {
188 [0x10] = 3, /* TERMINAL PROFILE */
189 [0xC2] = 4, /* ENVELOPE */
190 [0x12] = 2, /* FETCH */
191 [0x14] = 3, /* TERMINAL RESPONSE */
192};
193
194static const struct osim_cla_ins_case uicc_ins_case[] = {
195 {
196 .cla = 0x80,
197 .cla_mask = 0xFF,
198 .ins_tbl = uicc_ins_tbl_80,
199 }, {
200 .cla = 0x00,
201 .cla_mask = 0xF0,
202 .helper = uicc046_cla_ins_helper,
203 .ins_tbl = uicc_ins_tbl_046,
204 }, {
205 .cla = 0x40,
206 .cla_mask = 0xF0,
207 .helper = uicc046_cla_ins_helper,
208 .ins_tbl = uicc_ins_tbl_046,
209 }, {
210 .cla = 0x60,
211 .cla_mask = 0xF0,
212 .helper = uicc046_cla_ins_helper,
213 .ins_tbl = uicc_ins_tbl_046,
214 }, {
215 .cla = 0x80,
216 .cla_mask = 0xF0,
217 .ins_tbl = uicc_ins_tbl_8ce,
218 }, {
219 .cla = 0xC0,
220 .cla_mask = 0xF0,
221 .ins_tbl = uicc_ins_tbl_8ce,
222 }, {
223 .cla = 0xE0,
224 .cla_mask = 0xF0,
225 .ins_tbl = uicc_ins_tbl_8ce,
226 },
227};
228
229const struct osim_cla_ins_card_profile osim_uicc_cic_profile = {
230 .name = "UICC",
231 .description = "TS 102 221 / 3GPP TS 31.102",
232 .cic_arr = uicc_ins_case,
233 .cic_arr_size = ARRAY_SIZE(uicc_ins_case),
234};
235
236
237static const struct osim_cla_ins_case uicc_sim_ins_case[] = {
238 {
239 .cla = 0xA0,
240 .cla_mask = 0xFF,
241 .ins_tbl = gsm1111_ins_tbl,
242 }, {
243 .cla = 0x80,
244 .cla_mask = 0xFF,
245 .ins_tbl = uicc_ins_tbl_80,
246 }, {
247 .cla = 0x00,
248 .cla_mask = 0xF0,
249 .helper = uicc046_cla_ins_helper,
250 .ins_tbl = uicc_ins_tbl_046,
251 }, {
252 .cla = 0x40,
253 .cla_mask = 0xF0,
254 .helper = uicc046_cla_ins_helper,
255 .ins_tbl = uicc_ins_tbl_046,
256 }, {
257 .cla = 0x60,
258 .cla_mask = 0xF0,
259 .helper = uicc046_cla_ins_helper,
260 .ins_tbl = uicc_ins_tbl_046,
261 }, {
262 .cla = 0x80,
263 .cla_mask = 0xF0,
264 .ins_tbl = uicc_ins_tbl_8ce,
265 }, {
266 .cla = 0xC0,
267 .cla_mask = 0xF0,
268 .ins_tbl = uicc_ins_tbl_8ce,
269 }, {
270 .cla = 0xE0,
271 .cla_mask = 0xF0,
272 .ins_tbl = uicc_ins_tbl_8ce,
273 },
274};
275
276const struct osim_cla_ins_card_profile osim_uicc_sim_cic_profile = {
277 .name = "UICC+SIM",
278 .description = "TS 102 221 / 3GPP TS 31.102 + GSM TS 11.11",
279 .cic_arr = uicc_sim_ins_case,
280 .cic_arr_size = ARRAY_SIZE(uicc_sim_ins_case),
281};
282
283/* 3GPP TS 31.102 */
284const uint8_t usim_ins_case[256] = {
285 [0x88] = 4, /* AUTHENTICATE */
286};
287
288int osim_determine_apdu_case(const struct osim_cla_ins_card_profile *prof,
289 const uint8_t *hdr)
290{
291 uint8_t cla = hdr[0];
292 uint8_t ins = hdr[1];
293 int i;
294 int rc;
295
296 for (i = 0; i < prof->cic_arr_size; i++) {
297 const struct osim_cla_ins_case *cic = &prof->cic_arr[i];
298 if ((cla & cic->cla_mask) != cic->cla)
299 continue;
300 rc = cic->ins_tbl[ins];
301 switch (rc) {
302 case 0x80:
303 return cic->helper(cic, hdr);
304 case 0x00:
305 /* continue with fruther cic, rather than abort
306 * now */
307 continue;
308 default:
309 return rc;
310 }
311 }
312 return 0;
313}