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