2017-06-20 02:35:06 +00:00
/*! \file sim.h
* Routines for helping with SIM ( ISO / IEC 7816 - 4 more generally ) communication .
*/
2012-01-17 17:25:50 +00:00
# ifndef _OSMOCOM_SIM_H
# define _OSMOCOM_SIM_H
# include <osmocom/core/msgb.h>
# include <osmocom/core/linuxlist.h>
# define APDU_HDR_LEN 5
2017-06-19 22:17:59 +00:00
/*! command-response pairs cases
2012-09-16 16:40:02 +00:00
*
* Enumeration used to identify the APDU structure based on command - response pair case , as specified in ISO / IEC 7816 - 3 : 2006 ( E ) § 12.1 .
*/
2012-01-17 17:25:50 +00:00
enum osim_apdu_case {
2012-09-16 16:40:02 +00:00
APDU_CASE_1 , /*!< command header, no command data field, no response data field */
APDU_CASE_2S , /*!< command header, no command data field, response data field (short) */
APDU_CASE_2E , /*!< command header, no command data field, response data field (extended) */
APDU_CASE_3S , /*!< command header, command data field (short), no response data field */
APDU_CASE_3E , /*!< command header, command data field (extended), no response data field */
APDU_CASE_4S , /*!< command header, command data field (short), response data field (short) */
APDU_CASE_4E /*!< command header, command data field (extended), response data field (extended) */
2012-01-17 17:25:50 +00:00
} ;
2017-06-19 22:17:59 +00:00
/*! APDU/TPDU command header
2012-09-16 16:40:02 +00:00
*
* This structure encode an APDU / TPDU command header , as specified in ISO / IEC 7816 - 3 : 2006 ( E ) § 12.2 and § 12.3 .
* The APDU ( application layer ) can be encoded as different TPDUs ( transport layer ) , depending on the transport protocol used .
* The TPDU encoding by T = 1 of the APDU command header is identical to the APDU .
* The TPDU encoding by T = 0 of the APDU command header adds a Parameter 3 field , generally used instead of Lc / Le .
*
* @ todo have different structures for APDU , TPDU by T = 0 , and TPDU by T = 1.
*/
2012-01-17 17:25:50 +00:00
struct osim_apdu_cmd_hdr {
2012-09-16 16:40:02 +00:00
uint8_t cla ; /*!< CLASS byte */
uint8_t ins ; /*!< INSTRUCTION byte */
uint8_t p1 ; /*!< Parameter 1 byte */
uint8_t p2 ; /*!< Parameter 2 byte */
uint8_t p3 ; /*!< Parameter 3 byte, used for TPDU by T=0 */
2012-01-17 17:25:50 +00:00
} __attribute__ ( ( packed ) ) ;
# define msgb_apdu_dr(__x)
2017-06-19 22:17:59 +00:00
/*! APDU command body
2012-09-16 16:40:02 +00:00
*
* This structure encode a command body , as specified in ISO / IEC 7816 - 3 : 2006 ( E ) § 12.1 .
* The data and response contents should be provided along with this structure .
*/
2012-01-17 17:25:50 +00:00
struct osim_msgb_cb {
2012-09-16 16:40:02 +00:00
enum osim_apdu_case apduc ; /*!< command-response pair case, defining the encoding of Lc and Le */
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 */
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 */
uint16_t sw ; /*!< status word, composed of SW1 and SW2 bytes */
2014-05-04 11:42:38 +00:00
} __attribute__ ( ( __may_alias__ ) ) ;
2012-01-17 17:25:50 +00:00
# define OSIM_MSGB_CB(__msgb) ((struct osim_msgb_cb *)&((__msgb)->cb[0]))
2017-06-19 22:17:59 +00:00
/*! status word from msgb->cb */
2012-01-17 17:25:50 +00:00
# define msgb_apdu_case(__x) OSIM_MSGB_CB(__x)->apduc
# define msgb_apdu_lc(__x) OSIM_MSGB_CB(__x)->lc
# define msgb_apdu_le(__x) OSIM_MSGB_CB(__x)->le
# define msgb_apdu_sw(__x) OSIM_MSGB_CB(__x)->sw
2017-06-19 22:17:59 +00:00
/*! pointer to the command header of the APDU */
2012-01-17 17:25:50 +00:00
# define msgb_apdu_h(__x) ((struct osim_apdu_cmd_hdr *)(__x)->l2h)
# define msgb_apdu_dc(__x) ((__x)->l2h + sizeof(struct osim_apdu_cmd_hdr))
# define msgb_apdu_de(__x) ((__x)->l2h + sizeof(struct osim_apdu_cmd_hdr) + msgb_apdu_lc(__x))
2014-05-04 15:01:16 +00:00
/* FILES */
2012-01-17 17:25:50 +00:00
struct osim_file ;
struct osim_file_desc ;
struct osim_decoded_data ;
2017-06-19 22:17:59 +00:00
/*! Operations for a given File */
2012-01-17 17:25:50 +00:00
struct osim_file_ops {
2014-05-04 15:01:16 +00:00
/*! Parse binary file data into osim_decoded_data */
2012-01-17 17:25:50 +00:00
int ( * parse ) ( struct osim_decoded_data * dd ,
const struct osim_file_desc * desc ,
int len , uint8_t * data ) ;
2014-05-04 15:01:16 +00:00
/*! Encode osim_decoded_data into binary file */
2014-10-26 18:04:56 +00:00
struct msgb * ( * encode ) ( const struct osim_file_desc * desc ,
2012-01-17 17:25:50 +00:00
const struct osim_decoded_data * decoded ) ;
} ;
enum osim_element_type {
ELEM_T_NONE ,
ELEM_T_BOOL , /*!< a boolean flag */
ELEM_T_UINT8 , /*!< unsigned integer */
ELEM_T_UINT16 , /*!< unsigned integer */
ELEM_T_UINT32 , /*!< unsigned integer */
ELEM_T_STRING , /*!< generic string */
ELEM_T_BCD , /*!< BCD encoded digits */
ELEM_T_BYTES , /*!< BCD encoded digits */
ELEM_T_GROUP , /*!< group container, has siblings */
} ;
enum osim_element_repr {
ELEM_REPR_NONE ,
ELEM_REPR_DEC ,
ELEM_REPR_HEX ,
} ;
2017-06-19 22:17:59 +00:00
/*! A single decoded element inside a file */
2012-01-17 17:25:50 +00:00
struct osim_decoded_element {
struct llist_head list ;
enum osim_element_type type ;
enum osim_element_repr representation ;
const char * name ;
unsigned int length ;
union {
uint8_t u8 ;
uint16_t u16 ;
uint32_t u32 ;
uint8_t * buf ;
2014-05-04 15:01:16 +00:00
/*! A list of sibling decoded_items */
2012-01-17 17:25:50 +00:00
struct llist_head siblings ;
} u ;
} ;
2014-05-04 15:01:16 +00:00
/*! Decoded data for a single file, consisting of all decoded elements */
2012-01-17 17:25:50 +00:00
struct osim_decoded_data {
/*! file to which we belong */
const struct osim_file * file ;
/*! list of 'struct decoded_element' */
struct llist_head decoded_elements ;
} ;
enum osim_file_type {
TYPE_NONE ,
2014-05-04 15:01:16 +00:00
TYPE_DF , /*!< Dedicated File */
TYPE_ADF , /*!< Application Dedicated File */
TYPE_EF , /*!< Entry File */
TYPE_EF_INT , /*!< Internal Entry File */
2012-01-17 17:25:50 +00:00
} ;
enum osim_ef_type {
2014-05-04 15:01:16 +00:00
EF_TYPE_TRANSP , /*!< Transparent EF */
EF_TYPE_RECORD_FIXED , /*!< Fixed-Size Record EF */
EF_TYPE_RECORD_CYCLIC , /*!< Cyclic Record EF */
EF_TYPE_KEY , /*!< Key file as used in TETRA */
2012-01-17 17:25:50 +00:00
} ;
# define F_OPTIONAL 0x0001
2014-05-03 12:23:44 +00:00
# define SFI_NONE 0xFF
2012-01-17 17:25:50 +00:00
struct osim_file_desc {
struct llist_head list ; /*!< local element in list */
struct llist_head child_list ; /*!< list of children EF in DF */
struct osim_file_desc * parent ; /*!< parent DF */
2014-05-04 15:01:16 +00:00
enum osim_file_type type ; /*!< Type of the file (EF, DF, ...) */
enum osim_ef_type ef_type ; /*!< Type of the EF, if type == TYPE_EF */
2012-01-17 17:25:50 +00:00
uint16_t fid ; /*!< File Identifier */
uint8_t sfid ; /*!< Short File IDentifier */
2014-10-26 18:04:56 +00:00
const uint8_t * df_name ;
2012-01-17 17:25:50 +00:00
uint8_t df_name_len ;
const char * short_name ; /*!< Short Name (like EF.ICCID) */
const char * long_name ; /*!< Long / description */
unsigned int flags ;
2014-05-04 15:01:16 +00:00
struct osim_file_ops ops ; /*!< Operations (parse/encode */
2014-05-03 12:22:12 +00:00
struct {
size_t min ; /*!< Minimum size of the file
( transparent ) or record in
cyclic / linear file */
size_t rec ; /*!< Recommended size */
} size ;
2012-01-17 17:25:50 +00:00
} ;
2017-06-19 22:17:59 +00:00
/*! A single instance of a file: Descriptor and contents */
2012-01-17 17:25:50 +00:00
struct osim_file {
2014-05-04 15:01:16 +00:00
/*! Descriptor for the file */
2012-01-17 17:25:50 +00:00
const struct osim_file_desc * desc ;
2014-05-04 15:01:16 +00:00
/*! Encoded file contents */
2012-01-17 17:25:50 +00:00
struct msgb * encoded_data ;
2014-05-04 15:01:16 +00:00
/*! Parsed/Decoded file contents */
2012-01-17 17:25:50 +00:00
struct osim_decoded_data * decoded_data ;
} ;
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-03 12:23:44 +00:00
# define EF(pfid, sfi, pns, pflags, pnl, ptype, smin, srec, pdec, penc) \
2012-01-17 17:25:50 +00:00
{ \
. fid = pfid , \
2014-05-03 12:23:44 +00:00
. sfid = sfi , \
2012-01-17 17:25:50 +00:00
. type = TYPE_EF , \
. ef_type = ptype , \
. short_name = pns , \
. long_name = pnl , \
. flags = pflags , \
. ops = { . encode = penc , . parse = pdec } , \
2014-05-03 12:22:12 +00:00
. size = { . min = smin , . rec = srec } , \
2012-01-17 17:25:50 +00:00
}
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-03 12:23:44 +00:00
# define EF_TRANSP(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
EF ( fid , sfi , ns , flags , nl , EF_TYPE_TRANSP , \
2014-05-03 12:22:12 +00:00
smin , srec , dec , enc )
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-03 12:23:44 +00:00
# define EF_TRANSP_N(fid, sfi, ns, flags, smin, srec, nl) \
EF_TRANSP ( fid , sfi , ns , flags , smin , srec , \
2014-05-03 12:22:12 +00:00
nl , & default_decode , NULL )
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-03 12:23:44 +00:00
# define EF_CYCLIC(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
EF ( fid , sfi , ns , flags , nl , EF_TYPE_RECORD_CYCLIC , \
2014-05-03 12:22:12 +00:00
smin , srec , dec , enc )
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-03 12:23:44 +00:00
# define EF_CYCLIC_N(fid, sfi, ns, flags, smin, srec, nl) \
EF_CYCLIC ( fid , sfi , ns , flags , smin , srec , nl , \
2014-05-03 12:22:12 +00:00
& default_decode , NULL )
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-03 12:23:44 +00:00
# define EF_LIN_FIX(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
EF ( fid , sfi , ns , flags , nl , EF_TYPE_RECORD_FIXED , \
2014-05-03 12:22:12 +00:00
smin , srec , dec , enc )
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-03 12:22:12 +00:00
# define EF_LIN_FIX_N(fid, sfi, ns, flags, smin, srec, nl) \
EF_LIN_FIX ( fid , sfi , ns , flags , smin , srec , nl , \
& default_decode , NULL )
2012-01-17 17:25:50 +00:00
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-04 14:31:24 +00:00
# define EF_KEY(fid, sfi, ns, flags, smin, srec, nl, dec, enc) \
EF ( fid , sfi , ns , flags , nl , EF_TYPE_KEY , \
smin , srec , dec , enc )
2014-05-04 15:01:16 +00:00
/*! Convenience macros for defining EF */
2014-05-04 14:31:24 +00:00
# define EF_KEY_N(fid, sfi, ns, flags, smin, srec, nl) \
EF_KEY ( fid , sfi , ns , flags , smin , srec , nl , \
& default_decode , NULL )
2012-01-17 17:25:50 +00:00
struct osim_file_desc *
2016-03-11 02:40:56 +00:00
osim_file_desc_find_name ( struct osim_file_desc * parent , const char * name ) ;
2012-01-17 17:25:50 +00:00
2016-03-11 02:35:07 +00:00
struct osim_file_desc *
2016-03-11 02:40:56 +00:00
osim_file_desc_find_fid ( struct osim_file_desc * parent , uint16_t fid ) ;
2016-03-11 02:35:07 +00:00
struct osim_file_desc *
2016-03-11 02:40:56 +00:00
osim_file_desc_find_sfid ( struct osim_file_desc * parent , uint8_t sfid ) ;
2016-03-11 02:35:07 +00:00
2014-05-04 15:01:16 +00:00
/* STATUS WORDS */
2012-01-17 17:25:50 +00:00
enum osim_card_sw_type {
SW_TYPE_NONE ,
SW_TYPE_STR ,
} ;
enum osim_card_sw_class {
SW_CLS_NONE ,
SW_CLS_OK ,
SW_CLS_POSTP ,
SW_CLS_WARN ,
SW_CLS_ERROR ,
} ;
2014-05-04 15:01:16 +00:00
/*! A card status word (SW) */
2012-01-17 17:25:50 +00:00
struct osim_card_sw {
2014-05-04 15:01:16 +00:00
/*! status word code (2 bytes) */
2012-01-17 17:25:50 +00:00
uint16_t code ;
2014-05-04 15:01:16 +00:00
/*! status word mask (2 bytes), to match range/prefix of SW */
2012-01-17 17:25:50 +00:00
uint16_t mask ;
enum osim_card_sw_type type ;
enum osim_card_sw_class class ;
union {
2014-05-04 15:01:16 +00:00
/*! Human-readable meaning of SW */
2012-01-17 17:25:50 +00:00
const char * str ;
} u ;
} ;
2012-09-19 18:55:54 +00:00
# define OSIM_CARD_SW_LAST (const struct osim_card_sw) { \
2012-01-17 17:25:50 +00:00
. code = 0 , . mask = 0 , . type = SW_TYPE_NONE , \
. class = SW_CLS_NONE , . u . str = NULL \
}
2017-06-19 22:17:59 +00:00
/*! A card profile (e.g. SIM card */
2012-01-17 17:25:50 +00:00
struct osim_card_profile {
const char * name ;
2014-05-04 15:01:16 +00:00
/*! Descriptor for the MF (root directory */
2012-01-17 17:25:50 +00:00
struct osim_file_desc * mf ;
2014-05-04 15:01:16 +00:00
/*! Array of pointers to status words */
2012-09-19 18:55:54 +00:00
const struct osim_card_sw * * sws ;
2012-01-17 17:25:50 +00:00
} ;
2012-09-19 18:55:54 +00:00
const struct osim_card_sw * osim_find_sw ( const struct osim_card_profile * cp ,
uint16_t sw ) ;
2013-03-04 17:52:33 +00:00
enum osim_card_sw_class osim_sw_class ( const struct osim_card_profile * cp ,
uint16_t sw_in ) ;
2012-09-19 18:55:54 +00:00
struct osim_card_hdl ;
2019-03-18 17:27:00 +00:00
char * osim_print_sw_buf ( char * buf , size_t buf_len , const struct osim_card_hdl * ch , uint16_t sw_in ) ;
2012-09-19 18:55:54 +00:00
char * osim_print_sw ( const struct osim_card_hdl * ch , uint16_t sw_in ) ;
2019-03-18 17:38:47 +00:00
char * osim_print_sw_c ( const void * ctx , const struct osim_card_hdl * ch , uint16_t sw_in ) ;
2012-09-19 18:55:54 +00:00
2012-01-17 17:25:50 +00:00
extern const struct tlv_definition ts102221_fcp_tlv_def ;
2015-04-11 17:31:03 +00:00
extern const struct value_string ts102221_fcp_vals [ 14 ] ;
2012-01-17 17:25:50 +00:00
/* 11.1.1.3 */
enum ts102221_fcp_tag {
UICC_FCP_T_FCP = 0x62 ,
UICC_FCP_T_FILE_SIZE = 0x80 ,
UICC_FCP_T_TOT_F_SIZE = 0x81 ,
UICC_FCP_T_FILE_DESC = 0x82 ,
UICC_FCP_T_FILE_ID = 0x83 ,
UICC_FCP_T_DF_NAME = 0x84 ,
UICC_FCP_T_SFID = 0x88 ,
UICC_FCP_T_LIFEC_STS = 0x8A ,
UICC_FCP_T_SEC_ATTR_REFEXP = 0x8B ,
UICC_FCP_T_SEC_ATTR_COMP = 0x8C ,
UICC_FCP_T_PROPRIETARY = 0xA5 ,
UICC_FCP_T_SEC_ATTR_EXP = 0xAB ,
UICC_FCP_T_PIN_STS_DO = 0xC6 ,
} ;
struct msgb * osim_new_apdumsg ( uint8_t cla , uint8_t ins , uint8_t p1 ,
uint8_t p2 , uint16_t lc , uint16_t le ) ;
2014-05-04 15:01:16 +00:00
/* CARD READERS */
2012-01-17 17:25:50 +00:00
2014-10-26 17:46:50 +00:00
enum osim_proto {
OSIM_PROTO_T0 = 0 ,
OSIM_PROTO_T1 = 1 ,
} ;
enum osim_reader_driver {
OSIM_READER_DRV_PCSC = 0 ,
OSIM_READER_DRV_OPENCT = 1 ,
OSIM_READER_DRV_SERIAL = 2 ,
} ;
2016-03-19 20:18:40 +00:00
struct osim_reader_ops {
const char * name ;
struct osim_reader_hdl * ( * reader_open ) ( int idx , const char * name , void * ctx ) ;
struct osim_card_hdl * ( * card_open ) ( struct osim_reader_hdl * rh , enum osim_proto proto ) ;
int ( * transceive ) ( struct osim_reader_hdl * rh , struct msgb * msg ) ;
} ;
2012-01-17 17:25:50 +00:00
struct osim_reader_hdl {
2017-06-19 22:17:59 +00:00
/*! member in global list of readers */
2012-01-17 17:25:50 +00:00
struct llist_head list ;
2014-10-26 17:47:30 +00:00
const struct osim_reader_ops * ops ;
2014-10-26 17:46:50 +00:00
uint32_t proto_supported ;
2012-01-17 17:25:50 +00:00
void * priv ;
2017-06-19 22:17:59 +00:00
/*! current card, if any */
2012-01-17 17:25:50 +00:00
struct osim_card_hdl * card ;
} ;
struct osim_card_hdl {
2017-06-19 22:17:59 +00:00
/*! member in global list of cards */
2012-01-17 17:25:50 +00:00
struct llist_head list ;
2017-06-19 22:17:59 +00:00
/*! reader through which card is accessed */
2012-01-17 17:25:50 +00:00
struct osim_reader_hdl * reader ;
2017-06-19 22:17:59 +00:00
/*! card profile */
2012-01-17 17:25:50 +00:00
struct osim_card_profile * prof ;
2017-06-19 22:17:59 +00:00
/*! card protocol */
2014-10-26 17:46:50 +00:00
enum osim_proto proto ;
2012-01-17 17:25:50 +00:00
2017-06-19 22:17:59 +00:00
/*! list of channels for this card */
2012-01-17 17:25:50 +00:00
struct llist_head channels ;
} ;
struct osim_chan_hdl {
2017-06-19 22:17:59 +00:00
/*! linked to card->channels */
2012-01-17 17:25:50 +00:00
struct llist_head list ;
2017-06-19 22:17:59 +00:00
/*! card to which this channel belongs */
2012-01-17 17:25:50 +00:00
struct osim_card_hdl * card ;
const struct osim_file_desc * cwd ;
} ;
/* reader.c */
int osim_transceive_apdu ( struct osim_chan_hdl * st , struct msgb * amsg ) ;
2014-10-26 17:46:50 +00:00
struct osim_reader_hdl * osim_reader_open ( enum osim_reader_driver drv , int idx ,
const char * name , void * ctx ) ;
struct osim_card_hdl * osim_card_open ( struct osim_reader_hdl * rh , enum osim_proto proto ) ;
2012-01-17 17:25:50 +00:00
# endif /* _OSMOCOM_SIM_H */