blob: 63b3000b5435f1c9ccb6e7aefe696f9472ba0451 [file] [log] [blame]
Neels Hofmeyr17518fe2017-06-20 04:35:06 +02001/*! \file core.c
2 * Core routines for SIM/UICC/USIM access. */
Harald Weltead418632012-09-10 10:49:59 +02003/*
4 * (C) 2012 by Harald Welte <laforge@gnumonks.org>
5 *
6 * All Rights Reserved
7 *
Harald Weltee08da972017-11-13 01:00:26 +09008 * SPDX-License-Identifier: GPL-2.0+
9 *
Harald Weltead418632012-09-10 10:49:59 +020010 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with this program; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 *
24 */
25
26
Harald Welted54c2ee2012-01-17 18:25:50 +010027#include <stdlib.h>
28#include <stdint.h>
Harald Welte76749602012-09-19 20:55:54 +020029#include <string.h>
Harald Welted54c2ee2012-01-17 18:25:50 +010030
31#include <osmocom/core/talloc.h>
32#include <osmocom/sim/sim.h>
33
Harald Weltead418632012-09-10 10:49:59 +020034struct osim_decoded_data *osim_file_decode(struct osim_file *file,
35 int len, uint8_t *data)
36{
37 struct osim_decoded_data *dd;
38
39 if (!file->desc->ops.parse)
40 return NULL;
41
42 dd = talloc_zero(file, struct osim_decoded_data);
Harald Weltedb2b52e2014-10-26 19:04:41 +010043 if (!dd)
44 return NULL;
Harald Weltead418632012-09-10 10:49:59 +020045 dd->file = file;
46
47 if (file->desc->ops.parse(dd, file->desc, len, data) < 0) {
48 talloc_free(dd);
49 return NULL;
50 } else
51 return dd;
52}
53
54struct msgb *osim_file_encode(const struct osim_file_desc *desc,
55 const struct osim_decoded_data *data)
56{
57 if (!desc->ops.encode)
58 return NULL;
59
60 return desc->ops.encode(desc, data);
61}
62
Harald Welted54c2ee2012-01-17 18:25:50 +010063static struct osim_decoded_element *
64__element_alloc(void *ctx, const char *name, enum osim_element_type type,
65 enum osim_element_repr repr)
66{
67 struct osim_decoded_element *elem;
68
69 elem = talloc_zero(ctx, struct osim_decoded_element);
70 if (!elem)
71 return NULL;
72 elem->name = name;
73 elem->type = type;
74 elem->representation = repr;
75
76 if (elem->type == ELEM_T_GROUP)
77 INIT_LLIST_HEAD(&elem->u.siblings);
78
79 return elem;
80}
81
82
83struct osim_decoded_element *
84element_alloc(struct osim_decoded_data *dd, const char *name,
85 enum osim_element_type type, enum osim_element_repr repr)
86{
87 struct osim_decoded_element *elem;
88
89 elem = __element_alloc(dd, name, type, repr);
90 if (!elem)
91 return NULL;
92
93 llist_add_tail(&elem->list, &dd->decoded_elements);
94
95 return elem;
96}
97
98struct osim_decoded_element *
99element_alloc_sub(struct osim_decoded_element *ee, const char *name,
100 enum osim_element_type type, enum osim_element_repr repr)
101{
102 struct osim_decoded_element *elem;
103
104 elem = __element_alloc(ee, name, type, repr);
105 if (!elem)
106 return NULL;
107
108 llist_add(&elem->list, &ee->u.siblings);
109
110 return elem;
111}
112
113
114void add_filedesc(struct osim_file_desc *root, const struct osim_file_desc *in, int num)
115{
116 int i;
117
118 for (i = 0; i < num; i++) {
119 struct osim_file_desc *ofd = talloc_memdup(root, &in[i], sizeof(*in));
120 llist_add_tail(&ofd->list, &root->child_list);
121 }
122}
123
124struct osim_file_desc *alloc_df(void *ctx, uint16_t fid, const char *name)
125{
126 struct osim_file_desc *mf;
127
128 mf = talloc_zero(ctx, struct osim_file_desc);
Harald Weltedb2b52e2014-10-26 19:04:41 +0100129 if (!mf)
130 return NULL;
Harald Welted54c2ee2012-01-17 18:25:50 +0100131 mf->type = TYPE_DF;
132 mf->fid = fid;
133 mf->short_name = name;
134 INIT_LLIST_HEAD(&mf->child_list);
135
136 return mf;
137}
138
139struct osim_file_desc *
140add_df_with_ef(struct osim_file_desc *parent,
141 uint16_t fid, const char *name,
142 const struct osim_file_desc *in, int num)
143{
144 struct osim_file_desc *df;
145
146 df = alloc_df(parent, fid, name);
Harald Weltedb2b52e2014-10-26 19:04:41 +0100147 if (!df)
148 return NULL;
Harald Welted54c2ee2012-01-17 18:25:50 +0100149 df->parent = parent;
150 llist_add_tail(&df->list, &parent->child_list);
151 add_filedesc(df, in, num);
152
153 return df;
154}
155
156struct osim_file_desc *
157add_adf_with_ef(struct osim_file_desc *parent,
158 const uint8_t *adf_name, uint8_t adf_name_len,
159 const char *name, const struct osim_file_desc *in,
160 int num)
161{
162 struct osim_file_desc *df;
163
164 df = alloc_df(parent, 0xffff, name);
Harald Weltedb2b52e2014-10-26 19:04:41 +0100165 if (!df)
166 return NULL;
Harald Welted54c2ee2012-01-17 18:25:50 +0100167 df->type = TYPE_ADF;
168 df->df_name = adf_name;
169 df->df_name_len = adf_name_len;
170 df->parent = parent;
171 llist_add_tail(&df->list, &parent->child_list);
172 add_filedesc(df, in, num);
173
174 return df;
175}
176
177struct osim_file_desc *
Harald Welte5ffb5032016-03-11 09:40:56 +0700178osim_file_desc_find_name(struct osim_file_desc *parent, const char *name)
Harald Welted54c2ee2012-01-17 18:25:50 +0100179{
180 struct osim_file_desc *ofd;
181 llist_for_each_entry(ofd, &parent->child_list, list) {
182 if (!strcmp(ofd->short_name, name)) {
183 return ofd;
184 }
185 }
186 return NULL;
187}
188
Harald Weltec28f4cd2016-03-11 09:35:07 +0700189struct osim_file_desc *
Harald Welte5ffb5032016-03-11 09:40:56 +0700190osim_file_desc_find_fid(struct osim_file_desc *parent, uint16_t fid)
Harald Weltec28f4cd2016-03-11 09:35:07 +0700191{
192 struct osim_file_desc *ofd;
193 llist_for_each_entry(ofd, &parent->child_list, list) {
194 if (ofd->fid == fid) {
195 return ofd;
196 }
197 }
198 return NULL;
199}
200
201struct osim_file_desc *
Harald Welte5ffb5032016-03-11 09:40:56 +0700202osim_file_desc_find_sfid(struct osim_file_desc *parent, uint8_t sfid)
Harald Weltec28f4cd2016-03-11 09:35:07 +0700203{
204 struct osim_file_desc *ofd;
205 llist_for_each_entry(ofd, &parent->child_list, list) {
Harald Welte5ffb5032016-03-11 09:40:56 +0700206 if (ofd->sfid == SFI_NONE)
207 continue;
Harald Weltec28f4cd2016-03-11 09:35:07 +0700208 if (ofd->sfid == sfid) {
209 return ofd;
210 }
211 }
212 return NULL;
213}
214
215
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200216/*! Generate an APDU message and initialize APDU command header
Kevin Redon43eabee2012-09-16 18:40:02 +0200217 * \param[in] cla CLASS byte
218 * \param[in] ins INSTRUCTION byte
219 * \param[in] p1 Parameter 1 byte
220 * \param[in] p2 Parameter 2 byte
221 * \param[in] lc number of bytes in the command data field Nc, which will encoded in 0, 1 or 3 bytes into Lc
222 * \param[in] le maximum number of bytes expected in the response data field, which will encoded in 0, 1, 2 or 3 bytes into Le
223 * \returns an APDU message generated using provided APDU parameters
224 *
225 * This function generates an APDU message, as defined in ISO/IEC 7816-4:2005(E) §5.1.
226 * The APDU command header, command and response fields lengths are initialized using the parameters.
227 * The APDU case is determined by the command and response fields lengths.
Kevin Redon0f0ee322012-09-11 11:40:41 +0200228 */
Harald Welted54c2ee2012-01-17 18:25:50 +0100229struct msgb *osim_new_apdumsg(uint8_t cla, uint8_t ins, uint8_t p1,
230 uint8_t p2, uint16_t lc, uint16_t le)
231{
232 struct osim_apdu_cmd_hdr *ch;
233 struct msgb *msg = msgb_alloc(lc+le+sizeof(*ch)+2, "APDU");
234 if (!msg)
235 return NULL;
236
237 ch = (struct osim_apdu_cmd_hdr *) msgb_put(msg, sizeof(*ch));
Harald Welte76749602012-09-19 20:55:54 +0200238 msg->l2h = (uint8_t *) ch;
Harald Welted54c2ee2012-01-17 18:25:50 +0100239
240 ch->cla = cla;
241 ch->ins = ins;
242 ch->p1 = p1;
243 ch->p2 = p2;
244
245 msgb_apdu_lc(msg) = lc;
246 msgb_apdu_le(msg) = le;
247
248 if (lc == 0 && le == 0)
249 msgb_apdu_case(msg) = APDU_CASE_1;
250 else if (lc == 0 && le >= 1) {
251 if (le <= 256)
Kevin Redone07967f2012-09-11 11:44:18 +0200252 msgb_apdu_case(msg) = APDU_CASE_2S;
Harald Welted54c2ee2012-01-17 18:25:50 +0100253 else
Kevin Redone07967f2012-09-11 11:44:18 +0200254 msgb_apdu_case(msg) = APDU_CASE_2E;
Harald Welted54c2ee2012-01-17 18:25:50 +0100255 } else if (le == 0 && lc >= 1) {
256 if (lc <= 255)
Kevin Redone07967f2012-09-11 11:44:18 +0200257 msgb_apdu_case(msg) = APDU_CASE_3S;
Harald Welted54c2ee2012-01-17 18:25:50 +0100258 else
Kevin Redone07967f2012-09-11 11:44:18 +0200259 msgb_apdu_case(msg) = APDU_CASE_3E;
Harald Welted54c2ee2012-01-17 18:25:50 +0100260 } else if (lc >= 1 && le >= 1) {
Harald Welte76749602012-09-19 20:55:54 +0200261 if (lc <= 255 && le <= 256)
Kevin Redone07967f2012-09-11 11:44:18 +0200262 msgb_apdu_case(msg) = APDU_CASE_4S;
Harald Welted54c2ee2012-01-17 18:25:50 +0100263 else
Kevin Redone07967f2012-09-11 11:44:18 +0200264 msgb_apdu_case(msg) = APDU_CASE_4E;
Harald Welted54c2ee2012-01-17 18:25:50 +0100265 }
266
267 return msg;
268}
Harald Welte76749602012-09-19 20:55:54 +0200269
Harald Welte76749602012-09-19 20:55:54 +0200270
Harald Welte4a62eda2019-03-18 18:27:00 +0100271char *osim_print_sw_buf(char *buf, size_t buf_len, const struct osim_card_hdl *ch, uint16_t sw_in)
Harald Welte76749602012-09-19 20:55:54 +0200272{
273 const struct osim_card_sw *csw;
274
275 if (!ch || !ch->prof)
276 goto ret_def;
277
278 csw = osim_find_sw(ch->prof, sw_in);
279 if (!csw)
280 goto ret_def;
281
282 switch (csw->type) {
283 case SW_TYPE_STR:
Harald Welte4a62eda2019-03-18 18:27:00 +0100284 snprintf(buf, buf_len, "%04x (%s)", sw_in, csw->u.str);
Harald Welte76749602012-09-19 20:55:54 +0200285 break;
286 default:
287 goto ret_def;
288 }
289
Harald Welte4a62eda2019-03-18 18:27:00 +0100290 buf[buf_len-1] = '\0';
Harald Welte76749602012-09-19 20:55:54 +0200291
Harald Welte4a62eda2019-03-18 18:27:00 +0100292 return buf;
Harald Welte76749602012-09-19 20:55:54 +0200293
294ret_def:
Harald Welte4a62eda2019-03-18 18:27:00 +0100295 snprintf(buf, buf_len, "%04x (Unknown)", sw_in);
296 buf[buf_len-1] = '\0';
Harald Welte76749602012-09-19 20:55:54 +0200297
Harald Welte4a62eda2019-03-18 18:27:00 +0100298 return buf;
Harald Welte76749602012-09-19 20:55:54 +0200299}
300
Harald Welte4a62eda2019-03-18 18:27:00 +0100301char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in)
302{
303 /* FIXME: do we want to mark this as __thread? */
304 static char sw_print_buf[256];
305 return osim_print_sw_buf(sw_print_buf, sizeof(sw_print_buf), ch, sw_in);
306}
Harald Welte76749602012-09-19 20:55:54 +0200307
Harald Welte179f3572019-03-18 18:38:47 +0100308char *osim_print_sw_c(const void *ctx, const struct osim_card_hdl *ch, uint16_t sw_in)
309{
310 char *buf = talloc_size(ctx, 256);
311 if (!buf)
312 return NULL;
313 return osim_print_sw_buf(buf, 256, ch, sw_in);
314}
315
Harald Welte76749602012-09-19 20:55:54 +0200316const struct osim_card_sw *osim_find_sw(const struct osim_card_profile *cp,
317 uint16_t sw_in)
318{
319 const struct osim_card_sw **sw_lists = cp->sws;
320 const struct osim_card_sw *sw_list, *sw;
321
Vadim Yanitskiyd1c73232017-06-12 03:33:07 +0700322 for (sw_list = *sw_lists++; sw_list != NULL; sw_list = *sw_lists++) {
Harald Welte76749602012-09-19 20:55:54 +0200323 for (sw = sw_list; sw->code != 0 && sw->mask != 0; sw++) {
324 if ((sw_in & sw->mask) == sw->code)
325 return sw;
326 }
327 }
328 return NULL;
329}
Harald Welted83d2962013-03-04 17:52:33 +0000330
331enum osim_card_sw_class osim_sw_class(const struct osim_card_profile *cp,
332 uint16_t sw_in)
333{
334 const struct osim_card_sw *csw = osim_find_sw(cp, sw_in);
335
336 if (!csw)
337 return SW_CLS_NONE;
338
339 return csw->class;
340}
Harald Welte30115db2014-05-04 16:30:46 +0200341
342int default_decode(struct osim_decoded_data *dd,
343 const struct osim_file_desc *desc,
344 int len, uint8_t *data)
345{
346 struct osim_decoded_element *elem;
347
348 elem = element_alloc(dd, "Unknown Payload", ELEM_T_BYTES, ELEM_REPR_HEX);
349 elem->u.buf = talloc_memdup(elem, data, len);
350
351 return 0;
352}