blob: d7c4242763db57c976afc3be6afdc7a31d1b48fd [file] [log] [blame]
Harald Welted54c2ee2012-01-17 18:25:50 +01001#ifndef _OSMOCOM_SIM_H
2#define _OSMOCOM_SIM_H
3
4#include <osmocom/core/msgb.h>
5#include <osmocom/core/linuxlist.h>
6
7#define APDU_HDR_LEN 5
8
Kevin Redon43eabee2012-09-16 18:40:02 +02009/*!
10 * \file sim.h
11 * \brief Routines for helping with SIM (ISO/IEC 7816-4 more generally) communication.
12 */
13
14/*! \brief command-response pairs cases
15 *
16 * Enumeration used to identify the APDU structure based on command-response pair case , as specified in ISO/IEC 7816-3:2006(E) §12.1.
17 */
Harald Welted54c2ee2012-01-17 18:25:50 +010018enum osim_apdu_case {
Kevin Redon43eabee2012-09-16 18:40:02 +020019 APDU_CASE_1, /*!< command header, no command data field, no response data field */
20 APDU_CASE_2S, /*!< command header, no command data field, response data field (short) */
21 APDU_CASE_2E, /*!< command header, no command data field, response data field (extended) */
22 APDU_CASE_3S, /*!< command header, command data field (short), no response data field */
23 APDU_CASE_3E, /*!< command header, command data field (extended), no response data field */
24 APDU_CASE_4S, /*!< command header, command data field (short), response data field (short) */
25 APDU_CASE_4E /*!< command header, command data field (extended), response data field (extended) */
Harald Welted54c2ee2012-01-17 18:25:50 +010026};
27
Kevin Redon43eabee2012-09-16 18:40:02 +020028/*! \brief APDU/TPDU command header
29 *
30 * This structure encode an APDU/TPDU command header, as specified in ISO/IEC 7816-3:2006(E) §12.2 and §12.3.
31 * The APDU (application layer) can be encoded as different TPDUs (transport layer), depending on the transport protocol used.
32 * The TPDU encoding by T=1 of the APDU command header is identical to the APDU.
33 * The TPDU encoding by T=0 of the APDU command header adds a Parameter 3 field, generally used instead of Lc/Le.
34 *
35 * @todo have different structures for APDU, TPDU by T=0, and TPDU by T=1.
36 */
Harald Welted54c2ee2012-01-17 18:25:50 +010037struct osim_apdu_cmd_hdr {
Kevin Redon43eabee2012-09-16 18:40:02 +020038 uint8_t cla; /*!< CLASS byte */
39 uint8_t ins; /*!< INSTRUCTION byte */
40 uint8_t p1; /*!< Parameter 1 byte */
41 uint8_t p2; /*!< Parameter 2 byte */
42 uint8_t p3; /*!< Parameter 3 byte, used for TPDU by T=0 */
Harald Welted54c2ee2012-01-17 18:25:50 +010043} __attribute__ ((packed));
44
45#define msgb_apdu_dr(__x)
46
Kevin Redon43eabee2012-09-16 18:40:02 +020047/*! \brief APDU command body
48 *
49 * This structure encode a command body, as specified in ISO/IEC 7816-3:2006(E) §12.1.
50 * The data and response contents should be provided along with this structure.
51 */
Harald Welted54c2ee2012-01-17 18:25:50 +010052struct osim_msgb_cb {
Kevin Redon43eabee2012-09-16 18:40:02 +020053 enum osim_apdu_case apduc; /*!< command-response pair case, defining the encoding of Lc and Le */
54 uint16_t lc; /*!< number of bytes in the command data field Nc, which will encoded in 0, 1 or 3 bytes into Lc, depending on the case */
55 uint16_t le; /*!< maximum number of bytes expected in the response data field, which will encoded in 0, 1, 2 or 3 bytes into Le, depending on the case */
56 uint16_t sw; /*!< status word, composed of SW1 and SW2 bytes */
Harald Weltee8dd2bd2014-05-04 13:42:38 +020057} __attribute__((__may_alias__));
Harald Welted54c2ee2012-01-17 18:25:50 +010058#define OSIM_MSGB_CB(__msgb) ((struct osim_msgb_cb *)&((__msgb)->cb[0]))
59/*! \brief status word from msgb->cb */
60#define msgb_apdu_case(__x) OSIM_MSGB_CB(__x)->apduc
61#define msgb_apdu_lc(__x) OSIM_MSGB_CB(__x)->lc
62#define msgb_apdu_le(__x) OSIM_MSGB_CB(__x)->le
63#define msgb_apdu_sw(__x) OSIM_MSGB_CB(__x)->sw
64/*! \brief pointer to the command header of the APDU */
65#define msgb_apdu_h(__x) ((struct osim_apdu_cmd_hdr *)(__x)->l2h)
66
67#define msgb_apdu_dc(__x) ((__x)->l2h + sizeof(struct osim_apdu_cmd_hdr))
68#define msgb_apdu_de(__x) ((__x)->l2h + sizeof(struct osim_apdu_cmd_hdr) + msgb_apdu_lc(__x))
69
Harald Welte586d7102014-05-04 17:01:16 +020070/* FILES */
71
Harald Welted54c2ee2012-01-17 18:25:50 +010072struct osim_file;
73struct osim_file_desc;
74struct osim_decoded_data;
75
Harald Welte586d7102014-05-04 17:01:16 +020076/*! \brief Operations for a given File */
Harald Welted54c2ee2012-01-17 18:25:50 +010077struct osim_file_ops {
Harald Welte586d7102014-05-04 17:01:16 +020078 /*! Parse binary file data into osim_decoded_data */
Harald Welted54c2ee2012-01-17 18:25:50 +010079 int (*parse)(struct osim_decoded_data *dd,
80 const struct osim_file_desc *desc,
81 int len, uint8_t *data);
Harald Welte586d7102014-05-04 17:01:16 +020082 /*! Encode osim_decoded_data into binary file */
Harald Welte6729a972014-10-26 19:04:56 +010083 struct msgb * (*encode)(const struct osim_file_desc *desc,
Harald Welted54c2ee2012-01-17 18:25:50 +010084 const struct osim_decoded_data *decoded);
85};
86
87enum osim_element_type {
88 ELEM_T_NONE,
89 ELEM_T_BOOL, /*!< a boolean flag */
90 ELEM_T_UINT8, /*!< unsigned integer */
91 ELEM_T_UINT16, /*!< unsigned integer */
92 ELEM_T_UINT32, /*!< unsigned integer */
93 ELEM_T_STRING, /*!< generic string */
94 ELEM_T_BCD, /*!< BCD encoded digits */
95 ELEM_T_BYTES, /*!< BCD encoded digits */
96 ELEM_T_GROUP, /*!< group container, has siblings */
97};
98
99enum osim_element_repr {
100 ELEM_REPR_NONE,
101 ELEM_REPR_DEC,
102 ELEM_REPR_HEX,
103};
104
Harald Welte586d7102014-05-04 17:01:16 +0200105/*! \brief A single decoded element inside a file */
Harald Welted54c2ee2012-01-17 18:25:50 +0100106struct osim_decoded_element {
107 struct llist_head list;
108
109 enum osim_element_type type;
110 enum osim_element_repr representation;
111 const char *name;
112
113 unsigned int length;
114 union {
115 uint8_t u8;
116 uint16_t u16;
117 uint32_t u32;
118 uint8_t *buf;
Harald Welte586d7102014-05-04 17:01:16 +0200119 /*! A list of sibling decoded_items */
Harald Welted54c2ee2012-01-17 18:25:50 +0100120 struct llist_head siblings;
121 } u;
122};
123
Harald Welte586d7102014-05-04 17:01:16 +0200124/*! Decoded data for a single file, consisting of all decoded elements */
Harald Welted54c2ee2012-01-17 18:25:50 +0100125struct osim_decoded_data {
126 /*! file to which we belong */
127 const struct osim_file *file;
128 /*! list of 'struct decoded_element' */
129 struct llist_head decoded_elements;
130};
131
132
133enum osim_file_type {
134 TYPE_NONE,
Harald Welte586d7102014-05-04 17:01:16 +0200135 TYPE_DF, /*!< Dedicated File */
136 TYPE_ADF, /*!< Application Dedicated File */
137 TYPE_EF, /*!< Entry File */
138 TYPE_EF_INT, /*!< Internal Entry File */
Harald Welted54c2ee2012-01-17 18:25:50 +0100139};
140
141enum osim_ef_type {
Harald Welte586d7102014-05-04 17:01:16 +0200142 EF_TYPE_TRANSP, /*!< Transparent EF */
143 EF_TYPE_RECORD_FIXED, /*!< Fixed-Size Record EF */
144 EF_TYPE_RECORD_CYCLIC, /*!< Cyclic Record EF */
145 EF_TYPE_KEY, /*!< Key file as used in TETRA */
Harald Welted54c2ee2012-01-17 18:25:50 +0100146};
147
148#define F_OPTIONAL 0x0001
149
Harald Welte2656e652014-05-03 14:23:44 +0200150#define SFI_NONE 0xFF
151
Harald Welted54c2ee2012-01-17 18:25:50 +0100152struct osim_file_desc {
153 struct llist_head list; /*!< local element in list */
154 struct llist_head child_list; /*!< list of children EF in DF */
155 struct osim_file_desc *parent; /*!< parent DF */
156
Harald Welte586d7102014-05-04 17:01:16 +0200157 enum osim_file_type type; /*!< Type of the file (EF, DF, ...) */
158 enum osim_ef_type ef_type; /*!< Type of the EF, if type == TYPE_EF */
Harald Welted54c2ee2012-01-17 18:25:50 +0100159
160 uint16_t fid; /*!< File Identifier */
161 uint8_t sfid; /*!< Short File IDentifier */
Harald Welte6729a972014-10-26 19:04:56 +0100162 const uint8_t *df_name;
Harald Welted54c2ee2012-01-17 18:25:50 +0100163 uint8_t df_name_len;
164
165 const char *short_name; /*!< Short Name (like EF.ICCID) */
166 const char *long_name; /*!< Long / description */
167 unsigned int flags;
168
Harald Welte586d7102014-05-04 17:01:16 +0200169 struct osim_file_ops ops; /*!< Operations (parse/encode */
Harald Welte1e0dfda2014-05-03 14:22:12 +0200170
171 struct {
172 size_t min; /*!< Minimum size of the file
173 (transparent) or record in
174 cyclic / linear file */
175 size_t rec; /*!< Recommended size */
176 } size;
Harald Welted54c2ee2012-01-17 18:25:50 +0100177};
178
Harald Welte586d7102014-05-04 17:01:16 +0200179/*! \brief A single instance of a file: Descriptor and contents */
Harald Welted54c2ee2012-01-17 18:25:50 +0100180struct osim_file {
Harald Welte586d7102014-05-04 17:01:16 +0200181 /*! Descriptor for the file */
Harald Welted54c2ee2012-01-17 18:25:50 +0100182 const struct osim_file_desc *desc;
183
Harald Welte586d7102014-05-04 17:01:16 +0200184 /*! Encoded file contents */
Harald Welted54c2ee2012-01-17 18:25:50 +0100185 struct msgb *encoded_data;
Harald Welte586d7102014-05-04 17:01:16 +0200186 /*! Parsed/Decoded file contents */
Harald Welted54c2ee2012-01-17 18:25:50 +0100187 struct osim_decoded_data *decoded_data;
188};
189
Harald Welte586d7102014-05-04 17:01:16 +0200190/*! Convenience macros for defining EF */
Harald Welte2656e652014-05-03 14:23:44 +0200191#define EF(pfid, sfi, pns, pflags, pnl, ptype, smin, srec, pdec, penc) \
Harald Welted54c2ee2012-01-17 18:25:50 +0100192 { \
193 .fid = pfid, \
Harald Welte2656e652014-05-03 14:23:44 +0200194 .sfid = sfi, \
Harald Welted54c2ee2012-01-17 18:25:50 +0100195 .type = TYPE_EF, \
196 .ef_type = ptype, \
197 .short_name = pns, \
198 .long_name = pnl, \
199 .flags = pflags, \
200 .ops = { .encode = penc, .parse = pdec }, \
Harald Welte1e0dfda2014-05-03 14:22:12 +0200201 .size = { .min = smin, .rec = srec}, \
Harald Welted54c2ee2012-01-17 18:25:50 +0100202 }
203
204
Harald Welte586d7102014-05-04 17:01:16 +0200205/*! Convenience macros for defining EF */
Harald Welte2656e652014-05-03 14:23:44 +0200206#define EF_TRANSP(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
207 EF(fid, sfi, ns, flags, nl, EF_TYPE_TRANSP, \
Harald Welte1e0dfda2014-05-03 14:22:12 +0200208 smin, srec, dec, enc)
Harald Welte586d7102014-05-04 17:01:16 +0200209/*! Convenience macros for defining EF */
Harald Welte2656e652014-05-03 14:23:44 +0200210#define EF_TRANSP_N(fid, sfi, ns, flags, smin, srec, nl) \
211 EF_TRANSP(fid, sfi, ns, flags, smin, srec, \
Harald Welte1e0dfda2014-05-03 14:22:12 +0200212 nl, &default_decode, NULL)
Harald Welted54c2ee2012-01-17 18:25:50 +0100213
Harald Welte586d7102014-05-04 17:01:16 +0200214/*! Convenience macros for defining EF */
Harald Welte2656e652014-05-03 14:23:44 +0200215#define EF_CYCLIC(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
216 EF(fid, sfi, ns, flags, nl, EF_TYPE_RECORD_CYCLIC, \
Harald Welte1e0dfda2014-05-03 14:22:12 +0200217 smin, srec, dec, enc)
Harald Welte586d7102014-05-04 17:01:16 +0200218/*! Convenience macros for defining EF */
Harald Welte2656e652014-05-03 14:23:44 +0200219#define EF_CYCLIC_N(fid, sfi, ns, flags, smin, srec, nl) \
220 EF_CYCLIC(fid, sfi, ns, flags, smin, srec, nl, \
Harald Welte1e0dfda2014-05-03 14:22:12 +0200221 &default_decode, NULL)
Harald Welted54c2ee2012-01-17 18:25:50 +0100222
Harald Welte586d7102014-05-04 17:01:16 +0200223/*! Convenience macros for defining EF */
Harald Welte2656e652014-05-03 14:23:44 +0200224#define EF_LIN_FIX(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
225 EF(fid, sfi, ns, flags, nl, EF_TYPE_RECORD_FIXED, \
Harald Welte1e0dfda2014-05-03 14:22:12 +0200226 smin, srec, dec, enc)
Harald Welte586d7102014-05-04 17:01:16 +0200227/*! Convenience macros for defining EF */
Harald Welte1e0dfda2014-05-03 14:22:12 +0200228#define EF_LIN_FIX_N(fid, sfi, ns, flags, smin, srec, nl) \
229 EF_LIN_FIX(fid, sfi, ns, flags, smin, srec, nl, \
230 &default_decode, NULL)
Harald Welted54c2ee2012-01-17 18:25:50 +0100231
Harald Welte586d7102014-05-04 17:01:16 +0200232/*! Convenience macros for defining EF */
Harald Welteaad7e062014-05-04 16:31:24 +0200233#define EF_KEY(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
234 EF(fid, sfi, ns, flags, nl, EF_TYPE_KEY, \
235 smin, srec, dec, enc)
Harald Welte586d7102014-05-04 17:01:16 +0200236/*! Convenience macros for defining EF */
Harald Welteaad7e062014-05-04 16:31:24 +0200237#define EF_KEY_N(fid, sfi, ns, flags, smin, srec, nl) \
238 EF_KEY(fid, sfi, ns, flags, smin, srec, nl, \
239 &default_decode, NULL)
240
241
Harald Welted54c2ee2012-01-17 18:25:50 +0100242struct osim_file_desc *
Harald Welte5ffb5032016-03-11 09:40:56 +0700243osim_file_desc_find_name(struct osim_file_desc *parent, const char *name);
Harald Welted54c2ee2012-01-17 18:25:50 +0100244
Harald Weltec28f4cd2016-03-11 09:35:07 +0700245struct osim_file_desc *
Harald Welte5ffb5032016-03-11 09:40:56 +0700246osim_file_desc_find_fid(struct osim_file_desc *parent, uint16_t fid);
Harald Weltec28f4cd2016-03-11 09:35:07 +0700247
248struct osim_file_desc *
Harald Welte5ffb5032016-03-11 09:40:56 +0700249osim_file_desc_find_sfid(struct osim_file_desc *parent, uint8_t sfid);
Harald Weltec28f4cd2016-03-11 09:35:07 +0700250
Harald Welte586d7102014-05-04 17:01:16 +0200251/* STATUS WORDS */
252
Harald Welted54c2ee2012-01-17 18:25:50 +0100253enum osim_card_sw_type {
254 SW_TYPE_NONE,
255 SW_TYPE_STR,
256};
257
258enum osim_card_sw_class {
259 SW_CLS_NONE,
260 SW_CLS_OK,
261 SW_CLS_POSTP,
262 SW_CLS_WARN,
263 SW_CLS_ERROR,
264};
265
Harald Welte586d7102014-05-04 17:01:16 +0200266/*! A card status word (SW) */
Harald Welted54c2ee2012-01-17 18:25:50 +0100267struct osim_card_sw {
Harald Welte586d7102014-05-04 17:01:16 +0200268 /*! status word code (2 bytes) */
Harald Welted54c2ee2012-01-17 18:25:50 +0100269 uint16_t code;
Harald Welte586d7102014-05-04 17:01:16 +0200270 /*! status word mask (2 bytes), to match range/prefix of SW */
Harald Welted54c2ee2012-01-17 18:25:50 +0100271 uint16_t mask;
272 enum osim_card_sw_type type;
273 enum osim_card_sw_class class;
274 union {
Harald Welte586d7102014-05-04 17:01:16 +0200275 /*! Human-readable meaning of SW */
Harald Welted54c2ee2012-01-17 18:25:50 +0100276 const char *str;
277 } u;
278};
279
Harald Welte76749602012-09-19 20:55:54 +0200280#define OSIM_CARD_SW_LAST (const struct osim_card_sw) { \
Harald Welted54c2ee2012-01-17 18:25:50 +0100281 .code = 0, .mask = 0, .type = SW_TYPE_NONE, \
282 .class = SW_CLS_NONE, .u.str = NULL \
283}
284
Harald Welte586d7102014-05-04 17:01:16 +0200285/*! \brief A card profile (e.g. SIM card */
Harald Welted54c2ee2012-01-17 18:25:50 +0100286struct osim_card_profile {
287 const char *name;
Harald Welte586d7102014-05-04 17:01:16 +0200288 /*! Descriptor for the MF (root directory */
Harald Welted54c2ee2012-01-17 18:25:50 +0100289 struct osim_file_desc *mf;
Harald Welte586d7102014-05-04 17:01:16 +0200290 /*! Array of pointers to status words */
Harald Welte76749602012-09-19 20:55:54 +0200291 const struct osim_card_sw **sws;
Harald Welted54c2ee2012-01-17 18:25:50 +0100292};
293
Harald Welte76749602012-09-19 20:55:54 +0200294const struct osim_card_sw *osim_find_sw(const struct osim_card_profile *cp,
295 uint16_t sw);
Harald Welted83d2962013-03-04 17:52:33 +0000296enum osim_card_sw_class osim_sw_class(const struct osim_card_profile *cp,
297 uint16_t sw_in);
Harald Welte76749602012-09-19 20:55:54 +0200298
299struct osim_card_hdl;
300char *osim_print_sw(const struct osim_card_hdl *ch, uint16_t sw_in);
301
Harald Welted54c2ee2012-01-17 18:25:50 +0100302extern const struct tlv_definition ts102221_fcp_tlv_def;
Holger Hans Peter Freytherc2b44582015-04-11 19:31:03 +0200303extern const struct value_string ts102221_fcp_vals[14];
Harald Welted54c2ee2012-01-17 18:25:50 +0100304
305/* 11.1.1.3 */
306enum ts102221_fcp_tag {
307 UICC_FCP_T_FCP = 0x62,
308 UICC_FCP_T_FILE_SIZE = 0x80,
309 UICC_FCP_T_TOT_F_SIZE = 0x81,
310 UICC_FCP_T_FILE_DESC = 0x82,
311 UICC_FCP_T_FILE_ID = 0x83,
312 UICC_FCP_T_DF_NAME = 0x84,
313 UICC_FCP_T_SFID = 0x88,
314 UICC_FCP_T_LIFEC_STS = 0x8A,
315 UICC_FCP_T_SEC_ATTR_REFEXP= 0x8B,
316 UICC_FCP_T_SEC_ATTR_COMP= 0x8C,
317 UICC_FCP_T_PROPRIETARY = 0xA5,
318 UICC_FCP_T_SEC_ATTR_EXP = 0xAB,
319 UICC_FCP_T_PIN_STS_DO = 0xC6,
320};
321
322struct msgb *osim_new_apdumsg(uint8_t cla, uint8_t ins, uint8_t p1,
323 uint8_t p2, uint16_t lc, uint16_t le);
324
Harald Welte586d7102014-05-04 17:01:16 +0200325/* CARD READERS */
326
Harald Welted54c2ee2012-01-17 18:25:50 +0100327struct osim_reader_ops;
328
Harald Welte55790aa2014-10-26 18:46:50 +0100329enum osim_proto {
330 OSIM_PROTO_T0 = 0,
331 OSIM_PROTO_T1 = 1,
332};
333
334enum osim_reader_driver {
335 OSIM_READER_DRV_PCSC = 0,
336 OSIM_READER_DRV_OPENCT = 1,
337 OSIM_READER_DRV_SERIAL = 2,
338};
339
Harald Welted54c2ee2012-01-17 18:25:50 +0100340struct osim_reader_hdl {
341 /*! \brief member in global list of readers */
342 struct llist_head list;
Harald Welte67354b12014-10-26 18:47:30 +0100343 const struct osim_reader_ops *ops;
Harald Welte55790aa2014-10-26 18:46:50 +0100344 uint32_t proto_supported;
Harald Welted54c2ee2012-01-17 18:25:50 +0100345 void *priv;
346 /*! \brief current card, if any */
347 struct osim_card_hdl *card;
348};
349
350struct osim_card_hdl {
351 /*! \brief member in global list of cards */
352 struct llist_head list;
353 /*! \brief reader through which card is accessed */
354 struct osim_reader_hdl *reader;
355 /*! \brief card profile */
356 struct osim_card_profile *prof;
Harald Welte55790aa2014-10-26 18:46:50 +0100357 /*! \brief card protocol */
358 enum osim_proto proto;
Harald Welted54c2ee2012-01-17 18:25:50 +0100359
360 /*! \brief list of channels for this card */
361 struct llist_head channels;
362};
363
364struct osim_chan_hdl {
365 /*! \brief linked to card->channels */
366 struct llist_head list;
367 /*! \brief card to which this channel belongs */
368 struct osim_card_hdl *card;
369 const struct osim_file_desc *cwd;
370};
371
372/* reader.c */
373int osim_transceive_apdu(struct osim_chan_hdl *st, struct msgb *amsg);
Harald Welte55790aa2014-10-26 18:46:50 +0100374struct osim_reader_hdl *osim_reader_open(enum osim_reader_driver drv, int idx,
375 const char *name, void *ctx);
376struct osim_card_hdl *osim_card_open(struct osim_reader_hdl *rh, enum osim_proto proto);
Harald Welted54c2ee2012-01-17 18:25:50 +0100377#endif /* _OSMOCOM_SIM_H */