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